Merge remote-tracking branch 'stable/linux-3.0.y' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / drivers / cmmb / siano / smschar.c
1 /****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
6
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.
11
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.
16
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/>.
19
20 ****************************************************************/
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/init.h>
24
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 */
33
34 //#include <asm/arch/mfp-pxa9xx.h>
35 //#include <asm/arch/mfp-pxa3xx.h>
36 //#include <asm/arch/gpio.h>
37 #include "smscoreapi.h"
38
39 #include "smscharioctl.h"
40 #ifdef CONFIG_ANDROID_POWER
41 #include <linux/android_power.h>
42 #endif
43
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      
47
48 struct smschar_device_t {
49         struct cdev cdev;       /*!< Char device structure */
50         wait_queue_head_t waitq;        /* Processes waiting */
51         int cancel_waitq;
52         spinlock_t lock;        /*!< critical section */
53         int pending_count;
54         struct list_head pending_data;  /*!< list of pending data */
55         struct smscore_buffer_t *currentcb;
56         int device_index;
57         struct smscore_device_t *coredev;
58         struct smscore_client_t *smsclient;
59 };
60
61 /*!  Holds the major number of the device node. may be changed at load
62 time.*/
63 int smschar_major = 0;
64
65 /*!  Holds the first minor number of the device node.
66 may be changed at load time.*/
67 int smschar_minor;  /*= 0*/
68
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);
72
73 struct smschar_device_t smschar_devices[SMSCHAR_NR_DEVS];
74 static int g_smschar_inuse =0 ;
75
76 static int g_pnp_status_changed = 1;
77 //wait_queue_head_t g_pnp_event;
78
79 static struct class *smschr_dev_class;
80 static int g_has_suspended =0 ;
81 static struct device* sms_power_dev ;
82
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;
88 /**
89  * unregisters sms client and returns all queued buffers
90  *
91  * @param dev pointer to the client context (smschar parameters block)
92  *
93  */
94 static void smschar_unregister_client(struct smschar_device_t *dev)
95 {
96         unsigned long flags;
97
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);
102
103                 spin_lock_irqsave(&dev->lock, flags);
104
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);
109
110                         smscore_putbuffer(dev->coredev, cb);
111                         dev->pending_count--;
112                 }
113
114                 if (dev->currentcb) {
115                         smscore_putbuffer(dev->coredev, dev->currentcb);
116                         dev->currentcb = NULL;
117                         dev->pending_count--;
118                 }
119
120                 smscore_unregister_client(dev->smsclient);
121                 dev->smsclient = NULL;
122
123                 spin_unlock_irqrestore(&dev->lock, flags);
124         }
125 }
126
127 /**
128  * queues incoming buffers into buffers queue
129  *
130  * @param context pointer to the client context (smschar parameters block)
131  * @param cb pointer to incoming buffer descriptor
132  *
133  * @return 0 on success, <0 on queue overflow.
134  */
135 static int smschar_onresponse(void *context, struct smscore_buffer_t *cb)
136 {
137         struct smschar_device_t *dev = context;
138         unsigned long flags;
139
140         if (!dev) {
141                 sms_err("recieved bad dev pointer\n");
142                 return -EFAULT;
143         }
144         spin_lock_irqsave(&dev->lock, flags);
145
146         if (dev->pending_count > SMS_CHR_MAX_Q_LEN) {
147                 spin_unlock_irqrestore(&dev->lock, flags);
148                 return -EBUSY;
149         }
150
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);
156         }
157
158         list_add_tail(&cb->entry, &dev->pending_data);
159         spin_unlock_irqrestore(&dev->lock, flags);
160 // only fr test , hzb
161 //     return 0;
162         if (waitqueue_active(&dev->waitq))
163                 wake_up_interruptible(&dev->waitq);
164
165         return 0;
166 }
167
168 /**
169  * handles device removal event
170  *
171  * @param context pointer to the client context (smschar parameters block)
172  *
173  */
174 static void smschar_onremove(void *context)
175 {
176         struct smschar_device_t *dev = (struct smschar_device_t *)context;
177
178         smschar_unregister_client(dev);
179         dev->coredev = NULL;
180 }
181
182 /**
183  * registers client associated with the node
184  *
185  * @param inode Inode concerned.
186  * @param file File concerned.
187  *
188  * @return 0 on success, <0 on error.
189  */
190 static int smschar_open(struct inode *inode, struct file *file)
191 {
192         struct smschar_device_t *dev = container_of(inode->i_cdev,
193                                                     struct smschar_device_t,
194                                                     cdev);
195         int rc = -ENODEV;
196
197        // if(g_has_suspended)
198          //  return rc;
199
200         sms_info("entering index %d\n", dev->device_index);
201
202         if (dev->coredev) {
203                 struct smsclient_params_t params;
204       #if 1
205
206                 if(g_has_opened_first==0 && dev->device_index==0)
207                 {
208                  smsspi_poweron();
209                  g_has_opened_first=1;
210                  printk("open first********\n");
211     }
212     else if(dev->device_index!=0)
213         g_has_opened_first=0;
214       /****************end*******************************/ 
215 #endif    
216       
217         //      down(&sem);
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;
223
224                 rc = smscore_register_client(dev->coredev, &params, &dev->smsclient);
225                 if (!rc)
226                         file->private_data = dev;
227         
228                 dev->cancel_waitq = 0;
229                 g_pnp_status_changed = 1;
230             g_has_opened++;     
231         //      up(&sem);
232         }
233   
234         if (rc)
235                 sms_err(" exiting, rc %d\n", rc);
236
237         return rc;
238 }
239
240 /**
241  * unregisters client associated with the node
242  *
243  * @param inode Inode concerned.
244  * @param file File concerned.
245  *
246  */
247 static int smschar_release(struct inode *inode, struct file *file)
248 {
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");
252             return 0;
253         }
254 */
255     //printk("release smschar,%d\n",g_has_opened);
256
257         smschar_unregister_client(file->private_data);
258 #if 1
259     if(!(--g_has_opened)&& (g_has_opened_first==0))//hzb rockchip@20100528 g_has_opened_first==0??????????
260     {
261         smscore_reset_device_drvs(dev->coredev);
262         smsspi_off();
263         g_has_opened_first = 0;
264         printk("release at the end******\n");
265     }
266 /*****************end**************************/
267 #endif
268         sms_info("exiting\n");
269         return 0;
270 }
271
272
273 /**
274  * copies data from buffers in incoming queue into a user buffer
275  *
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).
280  *
281  * @return Number of bytes read, or <0 on error.
282  */
283 static ssize_t smschar_read(struct file *file, char __user *buf,
284                             size_t count, loff_t *f_pos)
285 {
286         struct smschar_device_t *dev = file->private_data;
287         unsigned long flags;
288         int rc, copied = 0;
289
290         if (!buf) {
291                 sms_err("Bad pointer recieved from user.\n");
292                 return -EFAULT;
293         }
294         if (!dev->coredev || !dev->smsclient||g_has_suspended) {
295                 sms_err("no client\n");
296                 return -ENODEV;
297         }
298         rc = wait_event_interruptible(dev->waitq, !list_empty(&dev->pending_data)|| (dev->cancel_waitq));
299         if (rc < 0) {
300                 sms_err("wait_event_interruptible error %d\n", rc);
301                 return rc;
302         }
303         if (dev->cancel_waitq)
304                 return 0;
305         if (!dev->smsclient) {
306                 sms_err("no client\n");
307                 return -ENODEV;
308         }
309         spin_lock_irqsave(&dev->lock, flags);
310
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],
316                                  actual_size)) {
317                         sms_err("copy_to_user failed\n");
318                         spin_unlock_irqrestore(&dev->lock, flags);
319                         return -EFAULT;
320                 }
321                 copied += actual_size;
322                 cb->offset += actual_size;
323                 cb->size -= actual_size;
324
325                 if (!cb->size) {
326                         list_del(&cb->entry);
327                         smscore_putbuffer(dev->coredev, cb);
328                         dev->pending_count--;
329                 }
330         }
331         spin_unlock_irqrestore(&dev->lock, flags);
332         return copied;
333 }
334
335 /**
336  * sends the buffer to the associated device
337  *
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).
342  *
343  * @return Number of bytes read, or <0 on error.
344  */
345 static ssize_t smschar_write(struct file *file, const char __user *buf,
346                              size_t count, loff_t *f_pos)
347 {
348         struct smschar_device_t *dev;
349         void *buffer;
350
351          
352         if (file == NULL) {
353                 sms_err("file is NULL\n");
354                 return EINVAL;
355         }
356
357         if (file->private_data == NULL) {
358                 sms_err("file->private_data is NULL\n");
359                 return -EINVAL;
360         }
361
362         dev = file->private_data;
363         if (!dev->smsclient||g_has_suspended) {
364                 sms_err("no client\n");
365                 return -ENODEV;
366         }
367
368         buffer = kmalloc(ALIGN(count, SMS_ALLOC_ALIGNMENT) + SMS_DMA_ALIGNMENT,
369                          GFP_KERNEL | GFP_DMA);
370         if (buffer) {
371                 void *msg_buffer = (void *)SMS_ALIGN_ADDRESS(buffer);
372
373                 if (!copy_from_user(msg_buffer, buf, count))
374                 {
375                         smsclient_sendrequest(dev->smsclient, msg_buffer, count);
376                 }
377                 else
378                         count = 0;
379                 kfree(buffer);
380         }
381
382         return count;
383 }
384
385 static int smschar_mmap(struct file *file, struct vm_area_struct *vma)
386 {
387         struct smschar_device_t *dev = file->private_data;
388         return smscore_map_common_buffer(dev->coredev, vma);
389 }
390
391 /**
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.
395  *
396  * @param dev pointer to smschar parameters block
397  * @param touser pointer to a structure that receives incoming buffer offsets
398  *
399  * @return 0 on success, <0 on error.
400  */
401 static int smschar_wait_get_buffer(struct smschar_device_t *dev,
402                                    struct smschar_buffer_t *touser)
403 {
404         unsigned long flags;
405         int rc;
406
407         spin_lock_irqsave(&dev->lock, flags);
408
409         if (dev->currentcb) {
410                 smscore_putbuffer(dev->coredev, dev->currentcb);
411                 dev->currentcb = NULL;
412                 dev->pending_count--;
413         }
414
415         spin_unlock_irqrestore(&dev->lock, flags);
416
417
418         memset(touser, 0, sizeof(struct smschar_buffer_t));
419
420         rc = wait_event_interruptible(dev->waitq,
421                                       !list_empty(&dev->pending_data)
422                                       || (dev->cancel_waitq));
423         if (rc < 0) {
424                 sms_err("wait_event_interruptible error, rc=%d\n", rc);
425                 return rc;
426         }
427         if (dev->cancel_waitq) {
428                 touser->offset = 0;
429                 touser->size = 0;
430                 return 0;
431         }
432         if (!dev->smsclient) {
433                 sms_err("no client\n");
434                 return -ENODEV;
435         }
436
437         spin_lock_irqsave(&dev->lock, flags);
438
439
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;
445
446                 list_del(&cb->entry);
447
448                 dev->currentcb = cb;
449         } else {
450                 touser->offset = 0;
451                 touser->size = 0;
452         }
453
454         //sms_debug("offset %d, size %d", touser->offset,touser->size);
455      
456         spin_unlock_irqrestore(&dev->lock, flags);
457
458         return 0;
459 }
460
461 /**
462  * poll for data availability
463  *
464  * @param file File structure.
465  * @param wait kernel polling table.
466  *
467  * @return POLLIN flag if read data is available.
468  */
469 static unsigned int smschar_poll(struct file *file,
470                                  struct poll_table_struct *wait)
471 {
472         struct smschar_device_t *dev;
473         int mask = 0;
474
475         if (file == NULL) {
476                 sms_err("file is NULL\n");
477                 return EINVAL;
478         }
479
480         if (file->private_data == NULL) {
481                 sms_err("file->private_data is NULL\n");
482                 return -EINVAL;
483         }
484
485         dev = file->private_data;
486
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);
490         }
491
492         if (!list_empty(&dev->pending_data))
493                 mask |= POLLIN | POLLRDNORM;
494         return mask;
495 }
496
497 static int smschar_ioctl(struct inode *inode, struct file *file,
498                          unsigned int cmd, unsigned long arg)
499 {
500         struct smschar_device_t *dev = file->private_data;
501         void __user *up = (void __user *)arg;
502
503         if (!dev->coredev || !dev->smsclient||g_has_suspended) {
504                 sms_err("no client\n");
505                 return -ENODEV;
506         }
507     
508 //      sms_info("smscharioctl - command is 0x%x", cmd);
509         switch (cmd) {
510         case SMSCHAR_STARTUP:
511                 smsspi_poweron();
512                 return 0;
513         case SMSCHAR_SET_DEVICE_MODE:
514                 return smscore_set_device_mode(dev->coredev, (int)arg);
515
516         case SMSCHAR_GET_DEVICE_MODE:
517                 {
518                         if (put_user(smscore_get_device_mode(dev->coredev),
519                                      (int *)up))
520                                 return -EFAULT;
521                         break;
522                 }
523         case SMSCHAR_IS_DEVICE_PNP_EVENT:
524                 {
525                        printk("pnp event not supported\n") ;
526 #if 0
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))
533                                 return -EFAULT;
534 #endif 
535                         break;
536                 }
537         case SMSCHAR_GET_BUFFER_SIZE:
538                 {
539                         if (put_user
540                             (smscore_get_common_buffer_size(dev->coredev),
541                              (int *)up))
542                                 return -EFAULT;
543
544                         break;
545                 }
546
547         case SMSCHAR_WAIT_GET_BUFFER:
548                 {
549                         struct smschar_buffer_t touser;
550                         int rc;
551                         //sms_debug(" before wait_get_buffer"); 
552  
553                         rc = smschar_wait_get_buffer(dev, &touser);
554                         if (rc < 0)
555                                 return rc;
556
557                         if (copy_to_user(up, &touser, sizeof(struct smschar_buffer_t)))
558                                 return -EFAULT;
559                         //sms_debug(" after wait_get_buffer");  
560
561                         break;
562                 }
563         case SMSCHAR_CANCEL_WAIT_BUFFER:
564                 {
565                         dev->cancel_waitq = 1;
566                         wake_up_interruptible(&dev->waitq);
567                         break;
568                 }
569         case SMSCHAR_GET_FW_FILE_NAME:
570                 {
571             if (!up)
572                 return -EINVAL;
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);
575                 }
576         case SMSCHAR_SEND_FW_FILE:
577                 {
578                         if (!up)
579                                 return -EINVAL;
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);
582                 }
583         // leadcore add on 2010-01-07
584         case  SMSCHAR_GET_RESUME_FLAG:
585                  copy_to_user(up, &resume_flag, sizeof(int));
586                  return 0;
587                   
588         case  SMSCHAR_SET_RESUME_FLAG:
589                  copy_from_user(&resume_flag,up,sizeof(int));
590              return 0;
591
592                   
593         case  SMSCHAR_RESET_DEVICE_DRVS:
594          smsspi_off();
595              return  smscore_reset_device_drvs (dev->coredev);
596
597         default:
598                 return -ENOIOCTLCMD;
599         }
600
601         return 0;
602 }
603
604
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,
614 };
615
616 static int smschar_setup_cdev(struct smschar_device_t *dev, int index)
617 {
618         //struct device *smschr_dev;
619         int rc, devno = MKDEV(smschar_major, smschar_minor + index);
620
621         cdev_init(&dev->cdev, &smschar_fops);
622
623         dev->cdev.owner = THIS_MODULE;
624         dev->cdev.ops = &smschar_fops;
625
626         kobject_set_name(&dev->cdev.kobj, "Siano_sms%d", index);
627         rc = cdev_add(&dev->cdev, devno, 1);
628         
629         if (!index)
630                 device_create(smschr_dev_class, NULL, devno,NULL,"mdtvctrl");
631         else
632                 device_create(smschr_dev_class, NULL, devno, NULL,"mdtv%d", index);
633         
634         sms_info("exiting %p %d, rc %d", dev, index, rc);
635
636         return rc;
637 }
638
639 /**
640  * smschar callback that called when device plugged in/out. the function
641  * register or unregisters char device interface according to plug in/out
642  *
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
646  *
647  * @return 0 on success, <0 on error.
648  */
649 static int smschar_hotplug(struct smscore_device_t *coredev,
650                            struct device *device, int arrival)
651 {
652         int rc = 0, i;
653
654         sms_info("entering %d\n", arrival);
655
656         g_pnp_status_changed = 1;
657         if (arrival) {
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));
663
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].
669                                                pending_data);
670                                 spin_lock_init(&smschar_devices[i].lock);
671                                 init_waitqueue_head(&smschar_devices[i].waitq);
672
673                                 smschar_devices[i].coredev = coredev;
674                                 smschar_devices[i].device_index = i;
675                         }
676                         g_smschar_inuse = 1;
677 //                      wake_up_interruptible(&g_pnp_event);
678                 }
679         } else {
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);
686                         }
687
688                         g_smschar_inuse = 0;
689 //                      wake_up_interruptible(&g_pnp_event);
690                 }
691         }
692
693         sms_info("exiting, rc %d\n", rc);
694
695         return rc;              /* succeed */
696 }
697
698 void smschar_reset_device(void)
699 {
700     int i;
701     printk(KERN_EMERG "SMS1180:in smschar_reset_device\n") ;
702     for(i=0;i< SMSCHAR_NR_DEVS;i++)
703     {
704         smschar_devices[i].cancel_waitq = 1;
705         wake_up_interruptible(&smschar_devices[i].waitq) ;
706         smschar_unregister_client(&smschar_devices[i]) ;
707     }
708 }
709 void smschar_set_suspend(int suspend_on)// 1: suspended ,0:resume  
710 {
711     printk(KERN_EMERG "SMS1180 : suspend_on = %d\n",suspend_on) ;
712     if(suspend_on) 
713        g_has_suspended = 1;
714     else 
715        g_has_suspended = 0;
716 }
717
718 EXPORT_SYMBOL(smschar_reset_device) ;
719 EXPORT_SYMBOL(smschar_set_suspend) ;
720
721 static ssize_t
722 sms_suspend_state_show(struct device *dev, struct device_attribute *attr, char *buf)
723 {
724     return sprintf(buf,"%d",sms_suspend_count) ;
725 }
726 static ssize_t
727 sms_suspend_state_store(struct device *dev, struct device_attribute *attr,
728                 const char *buffer, size_t count) 
729 {
730     sms_suspend_count =0 ;
731     return count ;
732 }
733
734 static DEVICE_ATTR(suspend,S_IRUGO|S_IWUGO,sms_suspend_state_show,sms_suspend_state_store);
735
736 #ifdef CONFIG_PM
737 #ifdef CONFIG_ANDROID_POWER
738 void smsspi_android_suspend_handler(android_early_suspend_t *h)
739 {
740 }
741
742 void smsspi_android_resume_handler(android_early_suspend_t *h)
743 {
744           int value;
745           if(g_has_opened)
746           {
747           resume_flag=1;
748           }
749           else
750           resume_flag=0;
751 }
752 static android_early_suspend_t smsspi_android_suspend = {
753         .level = 5,
754         .suspend = smsspi_android_suspend_handler,
755         .resume = smsspi_android_resume_handler,
756 };
757 #endif
758 #endif /*CONFIG_PM */
759 int smschar_register(void)
760 {
761         dev_t devno = MKDEV(smschar_major, smschar_minor);
762         int rc;
763
764         sms_info("registering device major=%d minor=%d\n", smschar_major,
765                  smschar_minor);
766         if (smschar_major) {
767                 rc = register_chrdev_region(devno, SMSCHAR_NR_DEVS, "smschar");
768         } else {
769                 rc = alloc_chrdev_region(&devno, smschar_minor,
770                                          SMSCHAR_NR_DEVS, "smschar");
771                 smschar_major = MAJOR(devno);
772         }
773
774         if (rc < 0) {
775                 sms_warn("smschar: can't get major %d\n", smschar_major);
776                 return rc;
777         }
778 //      init_waitqueue_head(&g_pnp_event);
779
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");
783                 return -1;
784         }
785         //sms_power_dev = device_create(smschr_dev_class,NULL,0,"%s","power_state") ;
786         //if(sms_power_dev)
787         //{
788            //rc = device_create_file(sms_power_dev, &dev_attr_suspend) ;
789         //}
790         //android_register_early_suspend(&smsspi_android_suspend);//hzb 
791         return smscore_register_hotplug(smschar_hotplug);
792 }
793
794 void smschar_unregister(void)
795 {
796         dev_t devno = MKDEV(smschar_major, smschar_minor);
797         
798         int i;
799         for( i = 0; i < SMSCHAR_NR_DEVS; i++)
800                 device_destroy(smschr_dev_class, MKDEV(smschar_major, i));
801         
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");
807 }