1 /****************************************************************
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ****************************************************************/
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/init.h>
25 #include <linux/kernel.h> /* printk() */
26 #include <linux/fs.h> /* everything... */
27 #include <linux/types.h> /* size_t */
28 #include <linux/cdev.h>
29 #include <linux/sched.h>
30 #include <linux/poll.h>
31 #include <asm/system.h> /* cli(), *_flags */
32 #include <linux/uaccess.h> /* copy_*_user */
34 //#include <asm/arch/mfp-pxa9xx.h>
35 //#include <asm/arch/mfp-pxa3xx.h>
36 //#include <asm/arch/gpio.h>
37 #include "smscoreapi.h"
39 #include "smscharioctl.h"
40 #ifdef CONFIG_ANDROID_POWER
41 #include <linux/android_power.h>
44 /* max number of packets allowed to be pending on queue*/
45 #define SMS_CHR_MAX_Q_LEN 15
46 #define SMSCHAR_NR_DEVS 17
48 struct smschar_device_t {
49 struct cdev cdev; /*!< Char device structure */
50 wait_queue_head_t waitq; /* Processes waiting */
52 spinlock_t lock; /*!< critical section */
54 struct list_head pending_data; /*!< list of pending data */
55 struct smscore_buffer_t *currentcb;
57 struct smscore_device_t *coredev;
58 struct smscore_client_t *smsclient;
61 /*! Holds the major number of the device node. may be changed at load
63 int smschar_major = 0;
65 /*! Holds the first minor number of the device node.
66 may be changed at load time.*/
67 int smschar_minor; /*= 0*/
69 /* macros that allow the load time parameters change*/
70 module_param(smschar_major, int, S_IRUGO);
71 module_param(smschar_minor, int, S_IRUGO);
73 struct smschar_device_t smschar_devices[SMSCHAR_NR_DEVS];
74 static int g_smschar_inuse =0 ;
76 static int g_pnp_status_changed = 1;
77 //wait_queue_head_t g_pnp_event;
79 static struct class *smschr_dev_class;
80 static int g_has_suspended =0 ;
81 static struct device* sms_power_dev ;
83 int sms_suspend_count ;
84 static struct semaphore sem;
85 static int g_has_opened=0;
86 static int g_has_opened_first=0;
87 static int resume_flag=0;
89 * unregisters sms client and returns all queued buffers
91 * @param dev pointer to the client context (smschar parameters block)
94 static void smschar_unregister_client(struct smschar_device_t *dev)
98 sms_info("entering... smschar_unregister_client....\n");
99 if (dev->coredev && dev->smsclient) {
100 dev->cancel_waitq = 1;
101 wake_up_interruptible(&dev->waitq);
103 spin_lock_irqsave(&dev->lock, flags);
105 while (!list_empty(&dev->pending_data)) {
106 struct smscore_buffer_t *cb =
107 (struct smscore_buffer_t *)dev->pending_data.next;
108 list_del(&cb->entry);
110 smscore_putbuffer(dev->coredev, cb);
111 dev->pending_count--;
114 if (dev->currentcb) {
115 smscore_putbuffer(dev->coredev, dev->currentcb);
116 dev->currentcb = NULL;
117 dev->pending_count--;
120 smscore_unregister_client(dev->smsclient);
121 dev->smsclient = NULL;
123 spin_unlock_irqrestore(&dev->lock, flags);
128 * queues incoming buffers into buffers queue
130 * @param context pointer to the client context (smschar parameters block)
131 * @param cb pointer to incoming buffer descriptor
133 * @return 0 on success, <0 on queue overflow.
135 static int smschar_onresponse(void *context, struct smscore_buffer_t *cb)
137 struct smschar_device_t *dev = context;
141 sms_err("recieved bad dev pointer\n");
144 spin_lock_irqsave(&dev->lock, flags);
146 if (dev->pending_count > SMS_CHR_MAX_Q_LEN) {
147 spin_unlock_irqrestore(&dev->lock, flags);
151 dev->pending_count++;
152 /* if data channel, remove header */
153 if (dev->device_index) {
154 cb->size -= sizeof(struct SmsMsgHdr_ST);
155 cb->offset += sizeof(struct SmsMsgHdr_ST);
158 list_add_tail(&cb->entry, &dev->pending_data);
159 spin_unlock_irqrestore(&dev->lock, flags);
160 // only fr test , hzb
162 if (waitqueue_active(&dev->waitq))
163 wake_up_interruptible(&dev->waitq);
169 * handles device removal event
171 * @param context pointer to the client context (smschar parameters block)
174 static void smschar_onremove(void *context)
176 struct smschar_device_t *dev = (struct smschar_device_t *)context;
178 smschar_unregister_client(dev);
183 * registers client associated with the node
185 * @param inode Inode concerned.
186 * @param file File concerned.
188 * @return 0 on success, <0 on error.
190 static int smschar_open(struct inode *inode, struct file *file)
192 struct smschar_device_t *dev = container_of(inode->i_cdev,
193 struct smschar_device_t,
197 // if(g_has_suspended)
200 sms_info("entering index %d\n", dev->device_index);
203 struct smsclient_params_t params;
206 if(g_has_opened_first==0 && dev->device_index==0)
209 g_has_opened_first=1;
210 printk("open first********\n");
212 else if(dev->device_index!=0)
213 g_has_opened_first=0;
214 /****************end*******************************/
218 params.initial_id = dev->device_index ? dev->device_index : SMS_HOST_LIB;
219 params.data_type = dev->device_index ? MSG_SMS_DAB_CHANNEL : 0;
220 params.onresponse_handler = smschar_onresponse;
221 params.onremove_handler = smschar_onremove;
222 params.context = dev;
224 rc = smscore_register_client(dev->coredev, ¶ms, &dev->smsclient);
226 file->private_data = dev;
228 dev->cancel_waitq = 0;
229 g_pnp_status_changed = 1;
235 sms_err(" exiting, rc %d\n", rc);
241 * unregisters client associated with the node
243 * @param inode Inode concerned.
244 * @param file File concerned.
247 static int smschar_release(struct inode *inode, struct file *file)
249 struct smschar_device_t *dev = file->private_data;
250 /* if(g_has_suspended ){
251 printk(KERN_EMERG "SMS1180: suspenede has released all client\n");
255 //printk("release smschar,%d\n",g_has_opened);
257 smschar_unregister_client(file->private_data);
259 if(!(--g_has_opened)&& (g_has_opened_first==0))//hzb rockchip@20100528 g_has_opened_first==0??????????
261 smscore_reset_device_drvs(dev->coredev);
263 g_has_opened_first = 0;
264 printk("release at the end******\n");
266 /*****************end**************************/
268 sms_info("exiting\n");
274 * copies data from buffers in incoming queue into a user buffer
276 * @param file File structure.
277 * @param buf Source buffer.
278 * @param count Size of source buffer.
279 * @param f_pos Position in file (ignored).
281 * @return Number of bytes read, or <0 on error.
283 static ssize_t smschar_read(struct file *file, char __user *buf,
284 size_t count, loff_t *f_pos)
286 struct smschar_device_t *dev = file->private_data;
291 sms_err("Bad pointer recieved from user.\n");
294 if (!dev->coredev || !dev->smsclient||g_has_suspended) {
295 sms_err("no client\n");
298 rc = wait_event_interruptible(dev->waitq, !list_empty(&dev->pending_data)|| (dev->cancel_waitq));
300 sms_err("wait_event_interruptible error %d\n", rc);
303 if (dev->cancel_waitq)
305 if (!dev->smsclient) {
306 sms_err("no client\n");
309 spin_lock_irqsave(&dev->lock, flags);
311 while (!list_empty(&dev->pending_data) && (copied < count)) {
312 struct smscore_buffer_t *cb =
313 (struct smscore_buffer_t *)dev->pending_data.next;
314 int actual_size = min(((int)count - copied), cb->size);
315 if (copy_to_user(&buf[copied], &((char *)cb->p)[cb->offset],
317 sms_err("copy_to_user failed\n");
318 spin_unlock_irqrestore(&dev->lock, flags);
321 copied += actual_size;
322 cb->offset += actual_size;
323 cb->size -= actual_size;
326 list_del(&cb->entry);
327 smscore_putbuffer(dev->coredev, cb);
328 dev->pending_count--;
331 spin_unlock_irqrestore(&dev->lock, flags);
336 * sends the buffer to the associated device
338 * @param file File structure.
339 * @param buf Source buffer.
340 * @param count Size of source buffer.
341 * @param f_pos Position in file (ignored).
343 * @return Number of bytes read, or <0 on error.
345 static ssize_t smschar_write(struct file *file, const char __user *buf,
346 size_t count, loff_t *f_pos)
348 struct smschar_device_t *dev;
353 sms_err("file is NULL\n");
357 if (file->private_data == NULL) {
358 sms_err("file->private_data is NULL\n");
362 dev = file->private_data;
363 if (!dev->smsclient||g_has_suspended) {
364 sms_err("no client\n");
368 buffer = kmalloc(ALIGN(count, SMS_ALLOC_ALIGNMENT) + SMS_DMA_ALIGNMENT,
369 GFP_KERNEL | GFP_DMA);
371 void *msg_buffer = (void *)SMS_ALIGN_ADDRESS(buffer);
373 if (!copy_from_user(msg_buffer, buf, count))
375 smsclient_sendrequest(dev->smsclient, msg_buffer, count);
385 static int smschar_mmap(struct file *file, struct vm_area_struct *vma)
387 struct smschar_device_t *dev = file->private_data;
388 return smscore_map_common_buffer(dev->coredev, vma);
392 * waits until buffer inserted into a queue. when inserted buffer offset
393 * are reportedto the calling process. previously reported buffer is
394 * returned to smscore pool.
396 * @param dev pointer to smschar parameters block
397 * @param touser pointer to a structure that receives incoming buffer offsets
399 * @return 0 on success, <0 on error.
401 static int smschar_wait_get_buffer(struct smschar_device_t *dev,
402 struct smschar_buffer_t *touser)
407 spin_lock_irqsave(&dev->lock, flags);
409 if (dev->currentcb) {
410 smscore_putbuffer(dev->coredev, dev->currentcb);
411 dev->currentcb = NULL;
412 dev->pending_count--;
415 spin_unlock_irqrestore(&dev->lock, flags);
418 memset(touser, 0, sizeof(struct smschar_buffer_t));
420 rc = wait_event_interruptible(dev->waitq,
421 !list_empty(&dev->pending_data)
422 || (dev->cancel_waitq));
424 sms_err("wait_event_interruptible error, rc=%d\n", rc);
427 if (dev->cancel_waitq) {
432 if (!dev->smsclient) {
433 sms_err("no client\n");
437 spin_lock_irqsave(&dev->lock, flags);
440 if (!list_empty(&dev->pending_data)) {
441 struct smscore_buffer_t *cb =
442 (struct smscore_buffer_t *)dev->pending_data.next;
443 touser->offset = cb->offset_in_common + cb->offset;
444 touser->size = cb->size;
446 list_del(&cb->entry);
454 //sms_debug("offset %d, size %d", touser->offset,touser->size);
456 spin_unlock_irqrestore(&dev->lock, flags);
462 * poll for data availability
464 * @param file File structure.
465 * @param wait kernel polling table.
467 * @return POLLIN flag if read data is available.
469 static unsigned int smschar_poll(struct file *file,
470 struct poll_table_struct *wait)
472 struct smschar_device_t *dev;
476 sms_err("file is NULL\n");
480 if (file->private_data == NULL) {
481 sms_err("file->private_data is NULL\n");
485 dev = file->private_data;
487 if (list_empty(&dev->pending_data)) {
488 sms_info("No data is ready, waiting for data recieve.\n");
489 poll_wait(file, &dev->waitq, wait);
492 if (!list_empty(&dev->pending_data))
493 mask |= POLLIN | POLLRDNORM;
497 static int smschar_ioctl(struct inode *inode, struct file *file,
498 unsigned int cmd, unsigned long arg)
500 struct smschar_device_t *dev = file->private_data;
501 void __user *up = (void __user *)arg;
503 if (!dev->coredev || !dev->smsclient||g_has_suspended) {
504 sms_err("no client\n");
508 // sms_info("smscharioctl - command is 0x%x", cmd);
510 case SMSCHAR_STARTUP:
513 case SMSCHAR_SET_DEVICE_MODE:
514 return smscore_set_device_mode(dev->coredev, (int)arg);
516 case SMSCHAR_GET_DEVICE_MODE:
518 if (put_user(smscore_get_device_mode(dev->coredev),
523 case SMSCHAR_IS_DEVICE_PNP_EVENT:
525 printk("pnp event not supported\n") ;
527 sms_info("Waiting for PnP event.\n");
528 wait_event_interruptible(g_pnp_event,
529 !g_pnp_status_changed);
530 g_pnp_status_changed = 0;
531 sms_info("PnP Event %d.\n", g_smschar_inuse);
532 if (put_user(g_smschar_inuse, (int *)up))
537 case SMSCHAR_GET_BUFFER_SIZE:
540 (smscore_get_common_buffer_size(dev->coredev),
547 case SMSCHAR_WAIT_GET_BUFFER:
549 struct smschar_buffer_t touser;
551 //sms_debug(" before wait_get_buffer");
553 rc = smschar_wait_get_buffer(dev, &touser);
557 if (copy_to_user(up, &touser, sizeof(struct smschar_buffer_t)))
559 //sms_debug(" after wait_get_buffer");
563 case SMSCHAR_CANCEL_WAIT_BUFFER:
565 dev->cancel_waitq = 1;
566 wake_up_interruptible(&dev->waitq);
569 case SMSCHAR_GET_FW_FILE_NAME:
573 return smscore_get_fw_filename(dev->coredev,((struct smschar_get_fw_filename_ioctl_t*)up)->mode,
574 ((struct smschar_get_fw_filename_ioctl_t*)up)->filename);
576 case SMSCHAR_SEND_FW_FILE:
580 return smscore_send_fw_file(dev->coredev,((struct smschar_send_fw_file_ioctl_t*)up)->fw_buf,
581 ((struct smschar_send_fw_file_ioctl_t *)up)->fw_size);
583 // leadcore add on 2010-01-07
584 case SMSCHAR_GET_RESUME_FLAG:
585 copy_to_user(up, &resume_flag, sizeof(int));
588 case SMSCHAR_SET_RESUME_FLAG:
589 copy_from_user(&resume_flag,up,sizeof(int));
593 case SMSCHAR_RESET_DEVICE_DRVS:
595 return smscore_reset_device_drvs (dev->coredev);
605 struct file_operations smschar_fops = {
606 .owner = THIS_MODULE,
607 .read = smschar_read,
608 .write = smschar_write,
609 .open = smschar_open,
610 .release = smschar_release,
611 .mmap = smschar_mmap,
612 .poll = smschar_poll,
613 .ioctl = smschar_ioctl,
616 static int smschar_setup_cdev(struct smschar_device_t *dev, int index)
618 //struct device *smschr_dev;
619 int rc, devno = MKDEV(smschar_major, smschar_minor + index);
621 cdev_init(&dev->cdev, &smschar_fops);
623 dev->cdev.owner = THIS_MODULE;
624 dev->cdev.ops = &smschar_fops;
626 kobject_set_name(&dev->cdev.kobj, "Siano_sms%d", index);
627 rc = cdev_add(&dev->cdev, devno, 1);
630 device_create(smschr_dev_class, NULL, devno,NULL,"mdtvctrl");
632 device_create(smschr_dev_class, NULL, devno, NULL,"mdtv%d", index);
634 sms_info("exiting %p %d, rc %d", dev, index, rc);
640 * smschar callback that called when device plugged in/out. the function
641 * register or unregisters char device interface according to plug in/out
643 * @param coredev pointer to device that is being plugged in/out
644 * @param device pointer to system device object
645 * @param arrival 1 on plug-on, 0 othewise
647 * @return 0 on success, <0 on error.
649 static int smschar_hotplug(struct smscore_device_t *coredev,
650 struct device *device, int arrival)
654 sms_info("entering %d\n", arrival);
656 g_pnp_status_changed = 1;
658 /* currently only 1 instance supported */
659 if (!g_smschar_inuse) {
660 /* data notification callbacks assignment */
661 memset(smschar_devices, 0, SMSCHAR_NR_DEVS *
662 sizeof(struct smschar_device_t));
664 /* Initialize each device. */
665 for (i = 0; i < SMSCHAR_NR_DEVS; i++) {
666 sms_info("create device %d", i);
667 smschar_setup_cdev(&smschar_devices[i], i);
668 INIT_LIST_HEAD(&smschar_devices[i].
670 spin_lock_init(&smschar_devices[i].lock);
671 init_waitqueue_head(&smschar_devices[i].waitq);
673 smschar_devices[i].coredev = coredev;
674 smschar_devices[i].device_index = i;
677 // wake_up_interruptible(&g_pnp_event);
680 /* currently only 1 instance supported */
681 if (g_smschar_inuse) {
682 /* Get rid of our char dev entries */
683 for (i = 0; i < SMSCHAR_NR_DEVS; i++) {
684 cdev_del(&smschar_devices[i].cdev);
685 sms_info("remove device %d\n", i);
689 // wake_up_interruptible(&g_pnp_event);
693 sms_info("exiting, rc %d\n", rc);
695 return rc; /* succeed */
698 void smschar_reset_device(void)
701 printk(KERN_EMERG "SMS1180:in smschar_reset_device\n") ;
702 for(i=0;i< SMSCHAR_NR_DEVS;i++)
704 smschar_devices[i].cancel_waitq = 1;
705 wake_up_interruptible(&smschar_devices[i].waitq) ;
706 smschar_unregister_client(&smschar_devices[i]) ;
709 void smschar_set_suspend(int suspend_on)// 1: suspended ,0:resume
711 printk(KERN_EMERG "SMS1180 : suspend_on = %d\n",suspend_on) ;
718 EXPORT_SYMBOL(smschar_reset_device) ;
719 EXPORT_SYMBOL(smschar_set_suspend) ;
722 sms_suspend_state_show(struct device *dev, struct device_attribute *attr, char *buf)
724 return sprintf(buf,"%d",sms_suspend_count) ;
727 sms_suspend_state_store(struct device *dev, struct device_attribute *attr,
728 const char *buffer, size_t count)
730 sms_suspend_count =0 ;
734 static DEVICE_ATTR(suspend,S_IRUGO|S_IWUGO,sms_suspend_state_show,sms_suspend_state_store);
737 #ifdef CONFIG_ANDROID_POWER
738 void smsspi_android_suspend_handler(android_early_suspend_t *h)
742 void smsspi_android_resume_handler(android_early_suspend_t *h)
752 static android_early_suspend_t smsspi_android_suspend = {
754 .suspend = smsspi_android_suspend_handler,
755 .resume = smsspi_android_resume_handler,
758 #endif /*CONFIG_PM */
759 int smschar_register(void)
761 dev_t devno = MKDEV(smschar_major, smschar_minor);
764 sms_info("registering device major=%d minor=%d\n", smschar_major,
767 rc = register_chrdev_region(devno, SMSCHAR_NR_DEVS, "smschar");
769 rc = alloc_chrdev_region(&devno, smschar_minor,
770 SMSCHAR_NR_DEVS, "smschar");
771 smschar_major = MAJOR(devno);
775 sms_warn("smschar: can't get major %d\n", smschar_major);
778 // init_waitqueue_head(&g_pnp_event);
780 smschr_dev_class= class_create(THIS_MODULE, "cmmb_demodulator");
781 if(IS_ERR(smschr_dev_class)){
782 sms_err("Could not create sms char device class\n");
785 //sms_power_dev = device_create(smschr_dev_class,NULL,0,"%s","power_state") ;
788 //rc = device_create_file(sms_power_dev, &dev_attr_suspend) ;
790 //android_register_early_suspend(&smsspi_android_suspend);//hzb
791 return smscore_register_hotplug(smschar_hotplug);
794 void smschar_unregister(void)
796 dev_t devno = MKDEV(smschar_major, smschar_minor);
799 for( i = 0; i < SMSCHAR_NR_DEVS; i++)
800 device_destroy(smschr_dev_class, MKDEV(smschar_major, i));
802 unregister_chrdev_region(devno, SMSCHAR_NR_DEVS);
803 smscore_unregister_hotplug(smschar_hotplug);
804 //android_unregister_early_suspend(&smsspi_android_suspend);
805 class_destroy(smschr_dev_class);
806 sms_info("unregistered\n");