Staging: comedi: Remove COMEDI_MODULES_MACRO
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / serial2002.c
index 0792617ebc3557c327d5c05f36389c6af1d1ae7d..85d127fb7eb1db9c2cbb37190512e07798906076 100644 (file)
@@ -393,15 +393,16 @@ static void serial_write(struct file *f, struct serial_data data)
        }
 }
 
-static void serial_2002_open(struct comedi_device *dev)
+static int serial_2002_open(struct comedi_device *dev)
 {
+       int result;
        char port[20];
 
        sprintf(port, "/dev/ttyS%d", devpriv->port);
        devpriv->tty = filp_open(port, O_RDWR, 0);
        if (IS_ERR(devpriv->tty)) {
-               printk("serial_2002: file open error = %ld\n",
-                      PTR_ERR(devpriv->tty));
+               result = (int)PTR_ERR(devpriv->tty);
+               printk("serial_2002: file open error = %d\n", result);
        } else {
                struct config_t {
 
@@ -411,29 +412,25 @@ static void serial_2002_open(struct comedi_device *dev)
                        int max;
                };
 
-               struct config_t dig_in_config[32];
-               struct config_t dig_out_config[32];
-               struct config_t chan_in_config[32];
-               struct config_t chan_out_config[32];
+               struct config_t *dig_in_config;
+               struct config_t *dig_out_config;
+               struct config_t *chan_in_config;
+               struct config_t *chan_out_config;
                int i;
 
-               for (i = 0; i < 32; i++) {
-                       dig_in_config[i].kind = 0;
-                       dig_in_config[i].bits = 0;
-                       dig_in_config[i].min = 0;
-                       dig_in_config[i].max = 0;
-                       dig_out_config[i].kind = 0;
-                       dig_out_config[i].bits = 0;
-                       dig_out_config[i].min = 0;
-                       dig_out_config[i].max = 0;
-                       chan_in_config[i].kind = 0;
-                       chan_in_config[i].bits = 0;
-                       chan_in_config[i].min = 0;
-                       chan_in_config[i].max = 0;
-                       chan_out_config[i].kind = 0;
-                       chan_out_config[i].bits = 0;
-                       chan_out_config[i].min = 0;
-                       chan_out_config[i].max = 0;
+               result = 0;
+               dig_in_config = kcalloc(32, sizeof(struct config_t),
+                               GFP_KERNEL);
+               dig_out_config = kcalloc(32, sizeof(struct config_t),
+                               GFP_KERNEL);
+               chan_in_config = kcalloc(32, sizeof(struct config_t),
+                               GFP_KERNEL);
+               chan_out_config = kcalloc(32, sizeof(struct config_t),
+                               GFP_KERNEL);
+               if (!dig_in_config || !dig_out_config
+                   || !chan_in_config || !chan_out_config) {
+                       result = -ENOMEM;
+                       goto err_alloc_configs;
                }
 
                tty_setspeed(devpriv->tty, devpriv->speed);
@@ -447,7 +444,7 @@ static void serial_2002_open(struct comedi_device *dev)
                                break;
                        } else {
                                int command, channel, kind;
-                               struct config_t *cur_config = 0;
+                               struct config_t *cur_config = NULL;
 
                                channel = data.value & 0x1f;
                                kind = (data.value >> 5) & 0x7;
@@ -574,8 +571,8 @@ static void serial_2002_open(struct comedi_device *dev)
                for (i = 0; i <= 4; i++) {
                        /*  Fill in subdev data */
                        struct config_t *c;
-                       unsigned char *mapping = 0;
-                       struct serial2002_range_table_t *range = 0;
+                       unsigned char *mapping = NULL;
+                       struct serial2002_range_table_t *range = NULL;
                        int kind = 0;
 
                        switch (i) {
@@ -613,7 +610,7 @@ static void serial_2002_open(struct comedi_device *dev)
                                }
                                break;
                        default:{
-                                       c = 0;
+                                       c = NULL;
                                }
                                break;
                        }
@@ -632,22 +629,23 @@ static void serial_2002_open(struct comedi_device *dev)
                                s = &dev->subdevices[i];
                                s->n_chan = chan;
                                s->maxdata = 0;
-                               if (s->maxdata_list) {
-                                       kfree(s->maxdata_list);
-                               }
+                               kfree(s->maxdata_list);
                                s->maxdata_list = maxdata_list =
                                    kmalloc(sizeof(unsigned int) * s->n_chan,
                                            GFP_KERNEL);
-                               if (s->range_table_list) {
-                                       kfree(s->range_table_list);
-                               }
+                               if (!s->maxdata_list)
+                                       break;  /* error handled below */
+                               kfree(s->range_table_list);
+                               s->range_table = NULL;
+                               s->range_table_list = NULL;
                                if (range) {
-                                       s->range_table = 0;
                                        s->range_table_list = range_table_list =
                                            kmalloc(sizeof
                                                    (struct
                                                     serial2002_range_table_t) *
                                                    s->n_chan, GFP_KERNEL);
+                                       if (!s->range_table_list)
+                                               break;  /* err handled below */
                                }
                                for (chan = 0, j = 0; j < 32; j++) {
                                        if (c[j].kind == kind) {
@@ -673,7 +671,35 @@ static void serial_2002_open(struct comedi_device *dev)
                                }
                        }
                }
+               if (i <= 4) {
+                       /* Failed to allocate maxdata_list or range_table_list
+                        * for a subdevice that needed it.  */
+                       result = -ENOMEM;
+                       for (i = 0; i <= 4; i++) {
+                               struct comedi_subdevice *s;
+
+                               s = &dev->subdevices[i];
+                               kfree(s->maxdata_list);
+                               s->maxdata_list = NULL;
+                               kfree(s->range_table_list);
+                               s->range_table_list = NULL;
+                       }
+               }
+
+err_alloc_configs:
+               kfree(dig_in_config);
+               kfree(dig_out_config);
+               kfree(chan_in_config);
+               kfree(chan_out_config);
+
+               if (result) {
+                       if (devpriv->tty) {
+                               filp_close(devpriv->tty, 0);
+                               devpriv->tty = NULL;
+                       }
+               }
        }
+       return result;
 }
 
 static void serial_2002_close(struct comedi_device *dev)
@@ -879,7 +905,7 @@ static int serial2002_detach(struct comedi_device *dev)
        int i;
 
        printk("comedi%d: serial2002: remove\n", dev->minor);
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < 5; i++) {
                s = &dev->subdevices[i];
                if (s->maxdata_list) {
                        kfree(s->maxdata_list);
@@ -892,3 +918,7 @@ static int serial2002_detach(struct comedi_device *dev)
 }
 
 COMEDI_INITCLEANUP(driver_serial2002);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");