From: <he...@us...> - 2005-03-20 22:35:27
|
Update of /cvsroot/gc-linux/linux/drivers/block In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15978/drivers/block Modified Files: gcn-aram.c Log Message: New ARAM rewrite. The driver uses now the driver model and the kernel DMA API. Index: gcn-aram.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/block/gcn-aram.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- gcn-aram.c 24 Feb 2005 21:36:42 -0000 1.5 +++ gcn-aram.c 20 Mar 2005 22:35:14 -0000 1.6 @@ -1,12 +1,12 @@ /* * drivers/block/gcn-aram.c * - * Nintendo GameCube ARAM block device - * Copyright (C) 2004 The GameCube Linux Team + * Nintendo GameCube Auxiliary RAM block driver + * Copyright (C) 2004-2005 The GameCube Linux Team + * Copyright (C) 2005 Todd Jeffreys <to...@vo...> + * Copyright (C) 2005 Albert Herranz * - * Based on previous work by Franz Lehner, apparently inspired on: - * z2ram.c - * Copyright (C) 1994 by Ingo Wilken (Ing...@in...) + * Based on previous work by Franz Lehner. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,231 +15,335 @@ * */ -#define DEVICE_NAME "ARAM" - -#include <linux/major.h> -#include <linux/vmalloc.h> -#include <linux/init.h> #include <linux/module.h> +#include <linux/major.h> #include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <asm/setup.h> -#include <asm/bitops.h> -#include <asm/pgtable.h> -#include <asm/cacheflush.h> -#include <linux/interrupt.h> - #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/hdreg.h> /* HDIO_GETGEO */ - +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> #include <asm/io.h> -#include <asm/scatterlist.h> -#define ARAM_MAJOR Z2RAM_MAJOR -#define HARD_SECTOR_SIZE 512 +#define DRV_MODULE_NAME "gcn-aram" +#define DRV_DESCRIPTION "Nintendo GameCube Auxiliary RAM block driver" +#define DRV_AUTHOR "Todd Jeffreys <to...@vo...>, " \ + "Albert Herranz" -//#define ARAM_DEBUG -//#define ARAM_DBG printk -#define ARAM_DBG(format, arg...); { } +static char aram_driver_version[] = "2.0"; -#define ARAM_SOUNDMEMORYOFFSET 0 -#define ARAM_BUFFERSIZE (16*1024*1024 - ARAM_SOUNDMEMORYOFFSET) +#define aram_printk(level, format, arg...) \ + printk(level DRV_MODULE_NAME ": " format , ## arg) -#define AI_DSP_CSR (void __iomem *)0xCC00500A -#define AI_CSR_RES (1<<0) -#define AI_CSR_PIINT (1<<1) -#define AI_CSR_HALT (1<<2) -#define AI_CSR_AIDINT (1<<3) -#define AI_CSR_AIDINTMASK (1<<4) -#define AI_CSR_ARINT (1<<5) -#define AI_CSR_ARINTMASK (1<<6) -#define AI_CSR_DSPINT (1<<7) -#define AI_CSR_DSPINTMASK (1<<8) -#define AI_CSR_DSPDMA (1<<9) -#define AI_CSR_RESETXXX (1<<11) +#ifdef ARAM_DEBUG +# define DBG(fmt, args...) \ + printk(KERN_ERR "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DBG(fmt, args...) +#endif -#define AR_SIZE (void __iomem*)0xCC005012 -#define AR_MODE (void __iomem*)0xCC005016 -#define AR_MODE_ACCELERATOR (1 << 0) +/* + * Hardware. + */ +#define ARAM_IRQ 6 -#define AR_REFRESH (void __iomem*)0xCC00501A +#define ARAM_DMA_ALIGN 0x1f /* 32 bytes */ -#define AR_DMA_MMADDR (void __iomem*)0xCC005020 -#define AR_DMA_ARADDR (void __iomem*)0xCC005024 -#define AR_DMA_CNT_H (void __iomem*)0xCC005028 -#define AR_DMA_CNT_L (void __iomem*)0xCC00502A -#define AR_DMA_CNT AR_DMA_CNT_H +#define DSP_BASE 0xcc005000 +#define DSP_SIZE 0x200 -#define ARAM_READ (1 << 31) -#define ARAM_WRITE 0 +#define DSP_IO_BASE ((void __iomem *)DSP_BASE) -#define ARAM_DMA_ALIGNMENT_MASK 0x1F +#define DSP_CSR 0x00a +#define DSP_CSR_RES (1<<0) +#define DSP_CSR_PIINT (1<<1) +#define DSP_CSR_HALT (1<<2) +#define DSP_CSR_AIDINT (1<<3) +#define DSP_CSR_AIDINTMASK (1<<4) +#define DSP_CSR_ARINT (1<<5) +#define DSP_CSR_ARINTMASK (1<<6) +#define DSP_CSR_DSPINT (1<<7) +#define DSP_CSR_DSPINTMASK (1<<8) +#define DSP_CSR_DSPDMA (1<<9) +#define DSP_CSR_RESETXXX (1<<11) -#define ARAM_IRQ 6 -#define IRQ_PARAM (void*)0xFFFFFFFA +#define AR_SIZE 0x012 -static spinlock_t aram_lock = SPIN_LOCK_UNLOCKED; -static struct block_device_operations aram_fops; -static struct gendisk *aram_gendisk; -static struct request_queue *aram_queue; -static struct request * volatile irq_request; -static u32 refCount; +#define AR_MODE 0x016 +#define AR_MODE_ACCELERATOR (1 << 0) -static inline void ARAM_StartDMA(void *mmAddr, unsigned long arAddr, - unsigned long length, unsigned long type) +#define AR_REFRESH 0x01a + +#define AR_DMA_MMADDR 0x020 + +#define AR_DMA_ARADDR 0x024 + +#define AR_DMA_CNT_H 0x028 +#define AR_READ (1 << 31) +#define AR_WRITE 0 + +#define AR_DMA_CNT_L 0x02a + +#define AR_DMA_CNT AR_DMA_CNT_H + +/* + * Driver settings + */ +#define ARAM_NAME "aram" +#define ARAM_MAJOR Z2RAM_MAJOR + +#define ARAM_SECTOR_SIZE PAGE_SIZE + +#define ARAM_SOUNDMEMORYOFFSET 0 +#define ARAM_BUFFERSIZE (16*1024*1024 - ARAM_SOUNDMEMORYOFFSET) + + + +struct aram_device { + spinlock_t lock; + + int irq; + void __iomem *io_base; + spinlock_t io_lock; + + struct block_device_operations fops; + struct gendisk *disk; + struct request_queue *queue; + + struct request *req; + dma_addr_t dma_addr; + size_t dma_len; + + int ref_count; + + struct platform_device pdev; /* must be last member */ +}; + + +/* get the aram device given the platform device of an aram device */ +#define to_aram_device(n) container_of(n,struct aram_device,pdev) + +/* + * Converts a request direction into a DMA data direction. + */ +static inline enum dma_data_direction rq_dir_to_dma_dir(struct request *req) { -#ifdef ARAM_DEBUG - if ((readw(AI_DSP_CSR) & AI_CSR_DSPDMA) || - (readl(AR_DMA_CNT) & 0x7FFFFFFF)) { - printk("StartDMA called, but there is already an outstanding DMA request!\n"); + if (rq_data_dir(req) == READ) { + return DMA_FROM_DEVICE; + } else { + return DMA_TO_DEVICE; } - else if (((u32)mmAddr & 0x1F) || (length & 0x1F)) { - printk("StartDMA called on unaligned data\n"); +} + +/* + * Converts a request direction into an ARAM data direction. + */ +static inline int rq_dir_to_aram_dir(struct request *req) +{ + if (rq_data_dir(req) == READ) { + return AR_READ; + } else { + return AR_WRITE; } -#endif - /* process */ - writel(virt_to_phys(mmAddr),AR_DMA_MMADDR); - writel(arAddr,AR_DMA_ARADDR); +} + + +/* + * Starts an ARAM DMA transfer. + */ +static void aram_start_dma_transfer(struct aram_device *adev, + unsigned long aram_addr) +{ + void __iomem *io_base = adev->io_base; + dma_addr_t dma_addr = adev->dma_addr; + size_t dma_len = adev->dma_len; + + /* DMA transfers require proper alignment */ + BUG_ON((dma_addr & ARAM_DMA_ALIGN) != 0 || + (dma_len & ARAM_DMA_ALIGN) != 0); + + writel(dma_addr, io_base + AR_DMA_MMADDR); + writel(aram_addr, io_base + AR_DMA_ARADDR); + /* writing the low-word kicks off the DMA */ - writel(type | length,AR_DMA_CNT); + writel(rq_dir_to_aram_dir(adev->req) | dma_len, io_base + AR_DMA_CNT); } -static irqreturn_t aram_irq(int irq,void *dev_id,struct pt_regs *regs) +/* + * Handles ARAM interrupts. + */ +static irqreturn_t aram_irq_handler(int irq, void *dev0, struct pt_regs *regs) { - unsigned long flags; - u16 tmp; + struct aram_device *adev = dev0; struct request *req; + u16 __iomem *csr_reg = adev->io_base + DSP_CSR; + u16 csr; + unsigned long flags; - if (readw(AI_DSP_CSR) & AI_CSR_ARINT) { -#ifdef ARAM_DEBUG - if (readw(AI_DSP_CSR) & AI_CSR_DSPDMA) { - flags = readl(AR_DMA_CNT); - do { - cpu_relax(); - } while(readw(AI_DSP_CSR) & AI_CSR_DSPDMA); - printk("Received interrupt before completion, number of bytes remaining was %lu\n",flags); - } - else if ((flags = (readl(AR_DMA_CNT) & 0x7FFFFFFF))) { - printk("Received interrupt before completion, number of bytes remaining was %lu\n",flags); - } -#endif - /* ack the int, but only ours */ - local_irq_save(flags); - tmp = readw(AI_DSP_CSR); - tmp &= ~(AI_CSR_AIDINT | AI_CSR_DSPINT); - writew(tmp,AI_DSP_CSR); - local_irq_restore(flags); + spin_lock_irqsave(&adev->io_lock, flags); + + csr = readw(csr_reg); + + /* + * Do nothing if the interrupt is not targetted for us. + * (We share this interrupt with the sound driver). + */ + if (!(csr & DSP_CSR_ARINT)) { + spin_unlock_irqrestore(&adev->io_lock, flags); + return IRQ_NONE; + } + + /* strictly ack the ARAM interrupt, and nothing more */ + csr &= ~(DSP_CSR_AIDINT | DSP_CSR_DSPINT); + writew(csr, csr_reg); + + /* pick up current request being serviced */ + req = adev->req; + adev->req = NULL; + + spin_unlock_irqrestore(&adev->io_lock, flags); - /* now process */ - spin_lock(&aram_lock); - if ((req = irq_request)) { - /* complete request */ - if (!end_that_request_first(req,1, - req->current_nr_sectors)) { - add_disk_randomness(req->rq_disk); - end_that_request_last(req); - } - else { - printk(KERN_ERR DEVICE_NAME " device still thinks there are requests but DMA has finished\n"); - } - irq_request = NULL; - /* start queue back up */ - blk_start_queue(aram_queue); - } - else { - printk(KERN_ERR DEVICE_NAME " received an interrupt but no irq_request set\n"); + if (req) { + if (!end_that_request_first(req, 1, req->current_nr_sectors)) { + add_disk_randomness(req->rq_disk); + end_that_request_last(req); } - spin_unlock(&aram_lock); - /* return handled */ - return IRQ_HANDLED; + dma_unmap_single(&adev->pdev.dev, adev->dma_addr, adev->dma_len, + rq_dir_to_dma_dir(req)); + spin_lock(&adev->lock); + blk_start_queue(adev->queue); + spin_unlock(&adev->lock); + } else { + aram_printk(KERN_ERR, "ignoring interrupt, no request\n"); } - return IRQ_NONE; -} + return IRQ_HANDLED; +} -static void do_aram_request(request_queue_t * q) +/* + * Performs block layer requests. + */ +static void aram_do_request(request_queue_t *q) { + struct aram_device *adev = q->queuedata; struct request *req; - unsigned long start; - unsigned long len; + unsigned long aram_addr; + size_t len; unsigned long flags; - - while ((req = elv_next_request(q))) { - /* get length */ - start = req->sector << 9; - len = req->current_nr_sectors << 9; - - if ((start + len) > ARAM_BUFFERSIZE) { - printk(KERN_ERR DEVICE_NAME - ": bad access: block=%lu, count=%lu\n", - (unsigned long)req->sector,len); - end_request(req, 0); - continue; - } - else if (irq_request) { /* already scheduled? */ + + req = elv_next_request(q); + while(req) { + spin_lock_irqsave(&adev->io_lock, flags); + + /* we can schedule just a single request each time */ + if (adev->req) { + spin_unlock_irqrestore(&adev->io_lock, flags); blk_stop_queue(q); - goto exit_func; + break; } - /* dequeue */ + blkdev_dequeue_request(req); + + /* ignore requests that we can't handle */ + if (!blk_fs_request(req)) { + spin_unlock_irqrestore(&adev->io_lock, flags); + continue; + } + + /* store the request being handled */ + adev->req = req; blk_stop_queue(q); - irq_request = req; - /* schedule DMA */ - if (rq_data_dir(req) == READ) { - invalidate_dcache_range((unsigned long)req->buffer, - (unsigned long)req->buffer + - len); - ARAM_StartDMA(req->buffer, - start + ARAM_SOUNDMEMORYOFFSET, len, - ARAM_READ); - } - else { - clean_dcache_range((unsigned long)req->buffer, - (unsigned long)req->buffer + len); - ARAM_StartDMA(req->buffer, - start + ARAM_SOUNDMEMORYOFFSET, len, - ARAM_WRITE); + + spin_unlock_irqrestore(&adev->io_lock, flags); + + /* calculate the ARAM address and length */ + aram_addr = req->sector << 9; + len = req->current_nr_sectors << 9; + + /* give up if the request goes out of bounds */ + if (aram_addr + len > ARAM_BUFFERSIZE) { + aram_printk(KERN_ERR, "bad access: block=%lu," + " size=%u\n", (unsigned long)req->sector, + len); + /* XXX correct? the request is already dequeued */ + end_request(req, 0); + continue; } - goto exit_func; + + BUG_ON(req->nr_phys_segments != 1); + + /* perform DMA mappings */ + adev->dma_len = len; + adev->dma_addr = dma_map_single(&adev->pdev.dev, req->buffer, + len, rq_dir_to_dma_dir(req)); + + /* start the DMA transfer */ + aram_start_dma_transfer(adev, + ARAM_SOUNDMEMORYOFFSET + aram_addr); + break; } - exit_func: } +/* + * Opens the ARAM device. + */ static int aram_open(struct inode *inode, struct file *filp) { + struct aram_device *adev = inode->i_bdev->bd_disk->private_data; unsigned long flags; - - ARAM_DBG("A-RAM Open device\n"); + int retval = 0; + + spin_lock_irqsave(&adev->lock, flags); + /* only allow a minor of 0 to be opened */ - if (iminor(inode)) - return -ENODEV; - /* allow multiple people to open this file */ - spin_lock_irqsave(&aram_lock,flags); - ++refCount; - spin_unlock_irqrestore(&aram_lock,flags); - return 0; + if (iminor(inode)) { + retval = -ENODEV; + goto out; + } + + /* honor exclusive open mode */ + if (adev->ref_count == -1 || + (adev->ref_count && (filp->f_flags & O_EXCL))) { + retval = -EBUSY; + goto out; + } + + if ((filp->f_flags & O_EXCL)) + adev->ref_count = -1; + else + adev->ref_count++; + +out: + spin_unlock_irqrestore(&adev->lock, flags); + return retval; } +/* + * Closes the ARAM device. + */ static int aram_release(struct inode *inode, struct file *filp) { + struct aram_device *adev = inode->i_bdev->bd_disk->private_data; unsigned long flags; - ARAM_DBG("A-RAM Close device\n"); - /* lower ref count */ - spin_lock_irqsave(&aram_lock,flags); - --refCount; - spin_unlock_irqrestore(&aram_lock,flags); + + spin_lock_irqsave(&adev->lock, flags); + if (adev->ref_count > 0) + adev->ref_count--; + else + adev->ref_count = 0; + spin_unlock_irqrestore(&adev->lock, flags); + return 0; } +/* + * Minimal ioctl for the ARAM device. + */ static int aram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct hd_geometry geo; - ARAM_DBG("A-RAM IOCTL\n"); - switch (cmd) { case BLKRAGET: case BLKFRAGET: @@ -265,106 +369,294 @@ } } -static int aram_revalidate(struct gendisk *disk) -{ - set_capacity(disk, ARAM_BUFFERSIZE >> 9); - return 0; -} static struct block_device_operations aram_fops = { .owner = THIS_MODULE, .open = aram_open, .release = aram_release, - .revalidate_disk = aram_revalidate, .ioctl = aram_ioctl, }; +/* + * + */ +static int aram_init_blk_dev(struct aram_device *adev) +{ + struct gendisk *disk; + struct request_queue *queue; + int retval; -int __init aram_init(void) + adev->ref_count = 0; + + retval = register_blkdev(ARAM_MAJOR, ARAM_NAME); + if (retval) + goto err_register_blkdev; + + retval = -ENOMEM; + spin_lock_init(&adev->lock); + spin_lock_init(&adev->io_lock); + queue = blk_init_queue(aram_do_request, &adev->lock); + if (!queue) + goto err_blk_init_queue; + + blk_queue_hardsect_size(queue, ARAM_SECTOR_SIZE); + blk_queue_dma_alignment(queue, ARAM_DMA_ALIGN); + blk_queue_max_phys_segments(queue, 1); + blk_queue_max_hw_segments(queue, 1); + queue->queuedata = adev; + adev->queue = queue; + + disk = alloc_disk(1); + if (!disk) + goto err_alloc_disk; + + disk->major = ARAM_MAJOR; + disk->first_minor = 0; + disk->fops = &aram_fops; + strcpy(disk->disk_name, ARAM_NAME); + strcpy(disk->devfs_name, disk->disk_name); + disk->queue = adev->queue; + set_capacity(disk, ARAM_BUFFERSIZE >> 9); + disk->private_data = adev; + adev->disk = disk; + + add_disk(adev->disk); + + retval = 0; + goto out; + +err_alloc_disk: + blk_cleanup_queue(adev->queue); +err_blk_init_queue: + unregister_blkdev(ARAM_MAJOR, ARAM_NAME); +err_register_blkdev: +out: + return retval; +} + +/* + * + */ +static void aram_exit_blk_dev(struct aram_device *adev) { - int ret; + if (adev->disk) { + del_gendisk(adev->disk); + put_disk(adev->disk); + } + if (adev->queue) + blk_cleanup_queue(adev->queue); + unregister_blkdev(ARAM_MAJOR, ARAM_NAME); +} + +/* + * + */ +static void aram_quiesce(struct aram_device *adev) +{ + u16 __iomem *csr_reg = adev->io_base + DSP_CSR; unsigned long flags; - /* get the irq */ - if ((ret=request_irq(ARAM_IRQ,aram_irq,SA_INTERRUPT | SA_SHIRQ,"ARAM", - IRQ_PARAM))) - goto out_irq; - - if ((ret=register_blkdev(ARAM_MAJOR, DEVICE_NAME))) - goto out_blkdev; - - ret = -ENOMEM; - aram_gendisk = alloc_disk(1); - if (!aram_gendisk) - goto out_disk; - - spin_lock_init(&aram_lock); - - aram_queue = blk_init_queue(do_aram_request, &aram_lock); - if (!aram_queue) - goto out_queue; + /* disable ARAM interrupts */ + spin_lock_irqsave(&adev->io_lock, flags); + writew(readw(csr_reg) & ~DSP_CSR_ARINTMASK, + csr_reg); + spin_unlock_irqrestore(&adev->io_lock, flags); - aram_gendisk->major = ARAM_MAJOR; - aram_gendisk->first_minor = 0; - aram_gendisk->fops = &aram_fops; - strcpy(aram_gendisk->disk_name, "aram"); - strcpy(aram_gendisk->devfs_name, aram_gendisk->disk_name); + /* wait until pending transfers are finished */ + while(readw(csr_reg) & DSP_CSR_DSPDMA) + cpu_relax(); +} - aram_gendisk->queue = aram_queue; +/* + * + */ +static int aram_init_irq(struct aram_device *adev) +{ + u16 __iomem *csr_reg = adev->io_base + DSP_CSR; + unsigned long flags; + int retval; - /* we can only have one segment at a time */ - blk_queue_max_phys_segments(aram_queue,1); - blk_queue_max_hw_segments(aram_queue,1); - /* make sectors equal to the pagesize */ - blk_queue_hardsect_size(aram_queue,HARD_SECTOR_SIZE); - /* set the DMA alignment */ - blk_queue_dma_alignment(aram_queue,ARAM_DMA_ALIGNMENT_MASK); - - set_capacity(aram_gendisk, ARAM_BUFFERSIZE >> 9); - add_disk(aram_gendisk); + /* request interrupt */ + retval = request_irq(adev->irq, aram_irq_handler, + SA_INTERRUPT | SA_SHIRQ, + DRV_MODULE_NAME, adev); + if (retval) { + aram_printk(KERN_ERR, "request of irq%d failed\n", adev->irq); + goto out; + } - /* lock this since audio driver might be using it */ - local_irq_save(flags); - writew(readw(AI_DSP_CSR) | AI_CSR_ARINTMASK | AI_CSR_PIINT,AI_DSP_CSR); - local_irq_restore(flags); + /* enable ARAM interrupts, and route them to the processor */ + spin_lock_irqsave(&adev->io_lock, flags); + writew(readw(csr_reg) | DSP_CSR_ARINTMASK | DSP_CSR_PIINT, csr_reg); + spin_unlock_irqrestore(&adev->io_lock, flags); - refCount = 0; +out: + return retval; +} + +/* + * + */ +static void aram_exit_irq(struct aram_device *adev) +{ + aram_quiesce(adev); + + free_irq(adev->irq, adev); +} + +/* + * + */ +static int aram_init(struct aram_device *adev, + struct resource *mem, int irq) +{ + int retval; + + memset(adev, 0, sizeof(*adev) - sizeof(adev->pdev)); + + adev->io_base = (void __iomem *)mem->start; + adev->irq = irq; + + retval = aram_init_blk_dev(adev); + if (!retval) { + retval = aram_init_irq(adev); + if (retval) { + aram_exit_blk_dev(adev); + } + } + return retval; +} + +/* + * + */ +static void aram_exit(struct aram_device *adev) +{ + aram_exit_blk_dev(adev); + aram_exit_irq(adev); +} + +/* + * Needed for platform devices. + */ +static void aram_dev_release(struct device *dev) +{ +} + + +static struct resource aram_resources[] = { + [0] = { + .start = DSP_BASE, + .end = DSP_BASE + DSP_SIZE -1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ARAM_IRQ, + .end = ARAM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct aram_device aram_device = { + .pdev = { + .name = ARAM_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(aram_resources), + .resource = aram_resources, + .dev = { + .release = aram_dev_release, + }, + }, +}; + + +/* + * + */ +static int aram_probe(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct aram_device *adev = to_aram_device(pdev); + struct resource *mem; + int irq; + int retval; + + retval = -ENODEV; + irq = platform_get_irq(pdev, 0); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem) { + retval = aram_init(adev, mem, irq); + } + return retval; +} + +/* + * + */ +static int aram_remove(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct aram_device *adev = to_aram_device(pdev); + + aram_exit(adev); - printk("ARAM info: Size = %u,Mode = 0x%x,Refresh = %u\n", - readw(AR_SIZE),readw(AR_MODE),readl(AR_REFRESH)); - return 0; +} - out_queue: - del_gendisk(aram_gendisk); - put_disk(aram_gendisk); - out_disk: - unregister_blkdev(ARAM_MAJOR, DEVICE_NAME); - out_blkdev: - free_irq(ARAM_IRQ,IRQ_PARAM); - out_irq: - return ret; +/* + * + */ +static void aram_shutdown(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct aram_device *adev = to_aram_device(pdev); + + aram_quiesce(adev); } -void __exit aram_cleanup(void) + +static struct device_driver aram_driver = { + .name = ARAM_NAME, + .bus = &platform_bus_type, + .probe = aram_probe, + .remove = aram_remove, + .shutdown = aram_shutdown, +}; + + +/* + * + */ +static int __init aram_init_module(void) { - free_irq(ARAM_IRQ,IRQ_PARAM); + int retval = 0; - blk_unregister_region(MKDEV(ARAM_MAJOR, 0), 256); - - if (unregister_blkdev(ARAM_MAJOR, DEVICE_NAME) != 0) - printk(KERN_ERR DEVICE_NAME ": unregister of device failed\n"); - - del_gendisk(aram_gendisk); - put_disk(aram_gendisk); - blk_cleanup_queue(aram_queue); - - return; + aram_printk(KERN_INFO, "%s - version %s\n", DRV_DESCRIPTION, + aram_driver_version); + + retval = driver_register(&aram_driver); + if (!retval) { + retval = platform_device_register(&aram_device.pdev); + } + + return retval; } -MODULE_AUTHOR("Todd Jeffreys <to...@vo...>"); -MODULE_DESCRIPTION("Gamecube ARAM block driver"); +/* + * + */ +static void __exit aram_exit_module(void) +{ + platform_device_unregister(&aram_device.pdev); + driver_unregister(&aram_driver); +} + +module_init(aram_init_module); +module_exit(aram_exit_module); + + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE("GPL"); -module_init(aram_init); -module_exit(aram_cleanup); + |