2 * Copyright (C) 2012 Spreadtrum Communications Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/cdev.h>
17 #include <linux/poll.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
21 #include <linux/spool.h>
22 #include <linux/sipc.h>
25 struct spool_init_data *init;
36 static struct class *spool_class;
38 static int spool_open(struct inode *inode, struct file *filp)
40 static struct spool_device *spool;
41 struct spool_sblock *sblock;
43 spool = container_of(inode->i_cdev, struct spool_device, cdev);
44 sblock = kmalloc(sizeof(struct spool_sblock), GFP_KERNEL);
48 filp->private_data = sblock;
50 sblock->dst = spool->init->dst;
51 sblock->channel = spool->init->channel;
56 static int spool_release(struct inode *inode, struct file *filp)
58 struct spool_sblock *sblock = filp->private_data;
65 static ssize_t spool_read(struct file *filp,
66 char __user *buf, size_t count, loff_t *ppos)
68 struct spool_sblock *sblock = filp->private_data;
72 struct sblock blk = {0};
74 if (filp->f_flags & O_NONBLOCK) {
78 if((ret = sblock_receive(sblock->dst, sblock->channel, &blk, timeout)) < 0){
79 pr_debug("spool_read: failed to receive block!\n");
83 rdsize = blk.length > count ? count : blk.length;
85 if(copy_to_user(buf, blk.addr, rdsize)){
86 pr_debug("spool_read: failed to copy to user!\n");
92 if(sblock_release(sblock->dst, sblock->channel, &blk)){
93 pr_debug("failed to release block!\n");
99 static ssize_t spool_write(struct file *filp,
100 const char __user *buf, size_t count, loff_t *ppos)
102 struct spool_sblock *sblock = filp->private_data;
107 struct sblock blk = {0};
110 if(filp->f_flags & O_NONBLOCK){
115 if((ret = sblock_get(sblock->dst, sblock->channel, &blk, timeout)) < 0){
116 printk(KERN_WARNING "spool_write: failed to get block!\n");
120 wrsize = (blk.length > len ? len : blk.length);
121 pr_debug("spool_write: blk_len %d, count %d, wsize %d\n", blk.length, len, wrsize);
122 if(copy_from_user(blk.addr, buf + pos, wrsize)){
123 printk(KERN_WARNING "spool_write: failed to copy from user!\n");
131 if(sblock_send(sblock->dst, sblock->channel, &blk)){
132 pr_debug("spool_write: failed to send block!");
135 pr_debug("spool_write len= %u, ret= %d\n", len, ret);
136 }while(len > 0 && ret == 0);
141 static unsigned int spool_poll(struct file *filp, poll_table *wait)
146 static long spool_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
151 static const struct file_operations spool_fops = {
153 .release = spool_release,
155 .write = spool_write,
157 .unlocked_ioctl = spool_ioctl,
158 .owner = THIS_MODULE,
159 .llseek = default_llseek,
162 static int __devinit spool_probe(struct platform_device *pdev)
164 struct spool_init_data *init = pdev->dev.platform_data;
165 struct spool_device *spool;
169 rval = sblock_create(init->dst, init->channel, init->txblocknum,
170 init->txblocksize, init->rxblocknum, init->rxblocksize);
172 printk(KERN_ERR "Failed to create sblock: %d\n", rval);
176 spool = kzalloc(sizeof(struct spool_device), GFP_KERNEL);
178 sblock_destroy(init->dst, init->channel);
179 printk(KERN_ERR "Failed to allocate spool_device\n");
183 rval = alloc_chrdev_region(&devid, 0, 1, init->name);
185 sblock_destroy(init->dst, init->channel);
187 printk(KERN_ERR "Failed to alloc spool chrdev\n");
190 cdev_init(&(spool->cdev), &spool_fops);
191 rval = cdev_add(&(spool->cdev), devid, 1);
193 sblock_destroy(init->dst, init->channel);
195 unregister_chrdev_region(devid, 1);
196 printk(KERN_ERR "Failed to add spool cdev\n");
200 spool->major = MAJOR(devid);
201 spool->minor = MINOR(devid);
203 device_create(spool_class, NULL,
204 MKDEV(spool->major, spool->minor),
205 NULL, "%s", init->name);
209 platform_set_drvdata(pdev, spool);
214 static int __devexit spool_remove(struct platform_device *pdev)
216 struct spool_device *spool = platform_get_drvdata(pdev);
217 device_destroy(spool_class, MKDEV(spool->major, spool->minor));
219 cdev_del(&(spool->cdev));
220 unregister_chrdev_region(
221 MKDEV(spool->major, spool->minor), 1);
223 sblock_destroy(spool->init->dst, spool->init->channel);
226 platform_set_drvdata(pdev, NULL);
231 static struct platform_driver spool_driver = {
233 .owner = THIS_MODULE,
236 .probe = spool_probe,
237 .remove = __devexit_p(spool_remove),
240 static int __init spool_init(void)
242 spool_class = class_create(THIS_MODULE, "spool");
243 if (IS_ERR(spool_class))
244 return PTR_ERR(spool_class);
246 return platform_driver_register(&spool_driver);
249 static void __exit spool_exit(void)
251 class_destroy(spool_class);
252 platform_driver_unregister(&spool_driver);
255 module_init(spool_init);
256 module_exit(spool_exit);
258 MODULE_AUTHOR("Qiu Yi");
259 MODULE_DESCRIPTION("SIPC/SPOOL driver");
260 MODULE_LICENSE("GPL");