Support Earthsoft PT2.

Signed-off-by: HIRANO Takahito <hiranot...@zng.info>
diff -r 7c0b887911cf linux/drivers/media/dvb/pt1/pt1.c
--- a/linux/drivers/media/dvb/pt1/pt1.c Mon Apr 05 22:56:43 2010 -0400
+++ b/linux/drivers/media/dvb/pt1/pt1.c Wed Apr 07 23:42:41 2010 +0900
@@ -1,5 +1,5 @@
 /*
- * driver for Earthsoft PT1
+ * driver for Earthsoft PT1/PT2
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranot...@zng.info>
  *
@@ -76,6 +76,10 @@
        struct pt1_adapter *adaps[PT1_NR_ADAPS];
        struct pt1_table *tables;
        struct task_struct *kthread;
+
+       struct mutex lock;
+       int power;
+       int reset;
 };
 
 struct pt1_adapter {
@@ -94,6 +98,11 @@
        struct dvb_frontend *fe;
        int (*orig_set_voltage)(struct dvb_frontend *fe,
                                fe_sec_voltage_t voltage);
+       int (*orig_sleep)(struct dvb_frontend *fe);
+       int (*orig_init)(struct dvb_frontend *fe);
+
+       fe_sec_voltage_t voltage;
+       int sleep;
 };
 
 #define pt1_printk(level, pt1, format, arg...) \
@@ -218,8 +227,10 @@
 static int pt1_enable_ram(struct pt1 *pt1)
 {
        int i, ret;
+       int phase;
        schedule_timeout_uninterruptible((HZ + 999) / 1000);
-       for (i = 0; i < 10; i++) {
+       phase = pt1->pdev->device == 0x211a ? 128 : 166;
+       for (i = 0; i < phase; i++) {
                ret = pt1_do_enable_ram(pt1);
                if (ret < 0)
                        return ret;
@@ -484,33 +495,47 @@
 }
 
 static void
-pt1_set_power(struct pt1 *pt1, int power, int lnb, int reset)
+pt1_update_power(struct pt1 *pt1)
 {
-       pt1_write_reg(pt1, 1, power | lnb << 1 | !reset << 3);
+       int bits;
+       int i;
+       struct pt1_adapter *adap;
+       static const int sleep_bits[] = {
+               1 << 4,
+               1 << 6 | 1 << 7,
+               1 << 5,
+               1 << 6 | 1 << 8,
+       };
+
+       bits = pt1->power | !pt1->reset << 3;
+       mutex_lock(&pt1->lock);
+       for (i = 0; i < PT1_NR_ADAPS; i++) {
+               adap = pt1->adaps[i];
+               switch (adap->voltage) {
+               case SEC_VOLTAGE_13: /* actually 11V */
+                       bits |= 1 << 1;
+                       break;
+               case SEC_VOLTAGE_18: /* actually 15V */
+                       bits |= 1 << 1 | 1 << 2;
+                       break;
+               default:
+                       break;
+               }
+
+               /* XXX: The bits should be changed depending on adap->sleep. */
+               bits |= sleep_bits[i];
+       }
+       pt1_write_reg(pt1, 1, bits);
+       mutex_unlock(&pt1->lock);
 }
 
 static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct pt1_adapter *adap;
-       int lnb;
 
        adap = container_of(fe->dvb, struct pt1_adapter, adap);
-
-       switch (voltage) {
-       case SEC_VOLTAGE_13: /* actually 11V */
-               lnb = 2;
-               break;
-       case SEC_VOLTAGE_18: /* actually 15V */
-               lnb = 3;
-               break;
-       case SEC_VOLTAGE_OFF:
-               lnb = 0;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       pt1_set_power(adap->pt1, 1, lnb, 0);
+       adap->voltage = voltage;
+       pt1_update_power(adap->pt1);
 
        if (adap->orig_set_voltage)
                return adap->orig_set_voltage(fe, voltage);
@@ -518,9 +543,37 @@
                return 0;
 }
 
+static int pt1_sleep(struct dvb_frontend *fe)
+{
+       struct pt1_adapter *adap;
+
+       adap = container_of(fe->dvb, struct pt1_adapter, adap);
+       adap->sleep = 1;
+       pt1_update_power(adap->pt1);
+
+       if (adap->orig_sleep)
+               return adap->orig_sleep(fe);
+       else
+               return 0;
+}
+
+static int pt1_wakeup(struct dvb_frontend *fe)
+{
+       struct pt1_adapter *adap;
+
+       adap = container_of(fe->dvb, struct pt1_adapter, adap);
+       adap->sleep = 0;
+       pt1_update_power(adap->pt1);
+       schedule_timeout_uninterruptible((HZ + 999) / 1000);
+
+       if (adap->orig_init)
+               return adap->orig_init(fe);
+       else
+               return 0;
+}
+
 static void pt1_free_adapter(struct pt1_adapter *adap)
 {
-       dvb_unregister_frontend(adap->fe);
        dvb_net_release(&adap->net);
        adap->demux.dmx.close(&adap->demux.dmx);
        dvb_dmxdev_release(&adap->dmxdev);
@@ -533,7 +586,7 @@
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static struct pt1_adapter *
-pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe)
+pt1_alloc_adapter(struct pt1 *pt1)
 {
        struct pt1_adapter *adap;
        void *buf;
@@ -550,8 +603,8 @@
 
        adap->pt1 = pt1;
 
-       adap->orig_set_voltage = fe->ops.set_voltage;
-       fe->ops.set_voltage = pt1_set_voltage;
+       adap->voltage = SEC_VOLTAGE_OFF;
+       adap->sleep = 1;
 
        buf = (u8 *)__get_free_page(GFP_KERNEL);
        if (!buf) {
@@ -592,17 +645,8 @@
 
        dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
 
-       ret = dvb_register_frontend(dvb_adap, fe);
-       if (ret < 0)
-               goto err_net_release;
-       adap->fe = fe;
-
        return adap;
 
-err_net_release:
-       dvb_net_release(&adap->net);
-       adap->demux.dmx.close(&adap->demux.dmx);
-       dvb_dmxdev_release(&adap->dmxdev);
 err_dmx_release:
        dvb_dmx_release(demux);
 err_unregister_adapter:
@@ -622,6 +666,62 @@
                pt1_free_adapter(pt1->adaps[i]);
 }
 
+static int pt1_init_adapters(struct pt1 *pt1)
+{
+       int i;
+       struct pt1_adapter *adap;
+       int ret;
+
+       for (i = 0; i < PT1_NR_ADAPS; i++) {
+               adap = pt1_alloc_adapter(pt1);
+               if (IS_ERR(adap)) {
+                       ret = PTR_ERR(adap);
+                       goto err;
+               }
+
+               adap->index = i;
+               pt1->adaps[i] = adap;
+       }
+       return 0;
+
+err:
+       while (i--)
+               pt1_free_adapter(pt1->adaps[i]);
+
+       return ret;
+}
+
+static void pt1_cleanup_frontend(struct pt1_adapter *adap)
+{
+       dvb_unregister_frontend(adap->fe);
+}
+
+static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe)
+{
+       int ret;
+
+       adap->orig_set_voltage = fe->ops.set_voltage;
+       adap->orig_sleep = fe->ops.sleep;
+       adap->orig_init = fe->ops.init;
+       fe->ops.set_voltage = pt1_set_voltage;
+       fe->ops.sleep = pt1_sleep;
+       fe->ops.init = pt1_wakeup;
+
+       ret = dvb_register_frontend(&adap->adap, fe);
+       if (ret < 0)
+               return ret;
+
+       adap->fe = fe;
+       return 0;
+}
+
+static void pt1_cleanup_frontends(struct pt1 *pt1)
+{
+       int i;
+       for (i = 0; i < PT1_NR_ADAPS; i++)
+               pt1_cleanup_frontend(pt1->adaps[i]);
+}
+
 struct pt1_config {
        struct va1j5jf8007s_config va1j5jf8007s_config;
        struct va1j5jf8007t_config va1j5jf8007t_config;
@@ -629,29 +729,63 @@
 
 static const struct pt1_config pt1_configs[2] = {
        {
-               { .demod_address = 0x1b },
-               { .demod_address = 0x1a },
+               {
+                       .demod_address = 0x1b,
+                       .frequency = VA1J5JF8007S_20MHZ,
+               },
+               {
+                       .demod_address = 0x1a,
+                       .frequency = VA1J5JF8007T_20MHZ,
+               },
        }, {
-               { .demod_address = 0x19 },
-               { .demod_address = 0x18 },
+               {
+                       .demod_address = 0x19,
+                       .frequency = VA1J5JF8007S_20MHZ,
+               },
+               {
+                       .demod_address = 0x18,
+                       .frequency = VA1J5JF8007T_20MHZ,
+               },
        },
 };
 
-static int pt1_init_adapters(struct pt1 *pt1)
+static const struct pt1_config pt2_configs[2] = {
+       {
+               {
+                       .demod_address = 0x1b,
+                       .frequency = VA1J5JF8007S_25MHZ,
+               },
+               {
+                       .demod_address = 0x1a,
+                       .frequency = VA1J5JF8007T_25MHZ,
+               },
+       }, {
+               {
+                       .demod_address = 0x19,
+                       .frequency = VA1J5JF8007S_25MHZ,
+               },
+               {
+                       .demod_address = 0x18,
+                       .frequency = VA1J5JF8007T_25MHZ,
+               },
+       },
+};
+
+static int pt1_init_frontends(struct pt1 *pt1)
 {
        int i, j;
        struct i2c_adapter *i2c_adap;
-       const struct pt1_config *config;
+       const struct pt1_config *configs, *config;
        struct dvb_frontend *fe[4];
-       struct pt1_adapter *adap;
        int ret;
 
        i = 0;
        j = 0;
 
        i2c_adap = &pt1->i2c_adap;
+       configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs;
        do {
-               config = &pt1_configs[i / 2];
+               config = &configs[i / 2];
 
                fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config,
                                            i2c_adap);
@@ -680,11 +814,9 @@
        } while (i < 4);
 
        do {
-               adap = pt1_alloc_adapter(pt1, fe[j]);
-               if (IS_ERR(adap))
+               ret = pt1_init_frontend(pt1->adaps[j], fe[j]);
+               if (ret < 0)
                        goto err;
-               adap->index = j;
-               pt1->adaps[j] = adap;
        } while (++j < 4);
 
        return 0;
@@ -694,7 +826,7 @@
                fe[i]->ops.release(fe[i]);
 
        while (j--)
-               pt1_free_adapter(pt1->adaps[j]);
+               dvb_unregister_frontend(fe[j]);
 
        return ret;
 }
@@ -889,9 +1021,12 @@
 
        kthread_stop(pt1->kthread);
        pt1_cleanup_tables(pt1);
+       pt1_cleanup_frontends(pt1);
+       pt1_disable_ram(pt1);
+       pt1->power = 0;
+       pt1->reset = 1;
+       pt1_update_power(pt1);
        pt1_cleanup_adapters(pt1);
-       pt1_disable_ram(pt1);
-       pt1_set_power(pt1, 0, 0, 1);
        i2c_del_adapter(&pt1->i2c_adap);
        pci_set_drvdata(pdev, NULL);
        kfree(pt1);
@@ -935,10 +1070,21 @@
                goto err_pci_iounmap;
        }
 
+       mutex_init(&pt1->lock);
        pt1->pdev = pdev;
        pt1->regs = regs;
        pci_set_drvdata(pdev, pt1);
 
+       ret = pt1_init_adapters(pt1);
+       if (ret < 0)
+               goto err_kfree;
+
+       mutex_init(&pt1->lock);
+
+       pt1->power = 0;
+       pt1->reset = 1;
+       pt1_update_power(pt1);
+
        i2c_adap = &pt1->i2c_adap;
        i2c_adap->class = I2C_CLASS_TV_DIGITAL;
        i2c_adap->algo = &pt1_i2c_algo;
@@ -947,9 +1093,7 @@
        i2c_set_adapdata(i2c_adap, pt1);
        ret = i2c_add_adapter(i2c_adap);
        if (ret < 0)
-               goto err_kfree;
-
-       pt1_set_power(pt1, 0, 0, 1);
+               goto err_pt1_cleanup_adapters;
 
        pt1_i2c_init(pt1);
        pt1_i2c_wait(pt1);
@@ -978,19 +1122,21 @@
 
        pt1_init_streams(pt1);
 
-       pt1_set_power(pt1, 1, 0, 1);
+       pt1->power = 1;
+       pt1_update_power(pt1);
        schedule_timeout_uninterruptible((HZ + 49) / 50);
 
-       pt1_set_power(pt1, 1, 0, 0);
+       pt1->reset = 0;
+       pt1_update_power(pt1);
        schedule_timeout_uninterruptible((HZ + 999) / 1000);
 
-       ret = pt1_init_adapters(pt1);
+       ret = pt1_init_frontends(pt1);
        if (ret < 0)
                goto err_pt1_disable_ram;
 
        ret = pt1_init_tables(pt1);
        if (ret < 0)
-               goto err_pt1_cleanup_adapters;
+               goto err_pt1_cleanup_frontends;
 
        kthread = kthread_run(pt1_thread, pt1, "pt1");
        if (IS_ERR(kthread)) {
@@ -1003,11 +1149,15 @@
 
 err_pt1_cleanup_tables:
        pt1_cleanup_tables(pt1);
+err_pt1_cleanup_frontends:
+       pt1_cleanup_frontends(pt1);
+err_pt1_disable_ram:
+       pt1_disable_ram(pt1);
+       pt1->power = 0;
+       pt1->reset = 1;
+       pt1_update_power(pt1);
 err_pt1_cleanup_adapters:
        pt1_cleanup_adapters(pt1);
-err_pt1_disable_ram:
-       pt1_disable_ram(pt1);
-       pt1_set_power(pt1, 0, 0, 1);
 err_i2c_del_adapter:
        i2c_del_adapter(i2c_adap);
 err_kfree:
@@ -1026,6 +1176,7 @@
 
 static struct pci_device_id pt1_id_table[] = {
        { PCI_DEVICE(0x10ee, 0x211a) },
+       { PCI_DEVICE(0x10ee, 0x222a) },
        { },
 };
 MODULE_DEVICE_TABLE(pci, pt1_id_table);
@@ -1053,5 +1204,5 @@
 module_exit(pt1_cleanup);
 
 MODULE_AUTHOR("Takahito HIRANO <hiranot...@zng.info>");
-MODULE_DESCRIPTION("Earthsoft PT1 Driver");
+MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
 MODULE_LICENSE("GPL");
diff -r 7c0b887911cf linux/drivers/media/dvb/pt1/va1j5jf8007s.c
--- a/linux/drivers/media/dvb/pt1/va1j5jf8007s.c        Mon Apr 05 22:56:43 
2010 -0400
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007s.c        Wed Apr 07 23:42:41 
2010 +0900
@@ -1,5 +1,5 @@
 /*
- * ISDB-S driver for VA1J5JF8007
+ * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranot...@zng.info>
  *
@@ -580,7 +580,7 @@
 
 static struct dvb_frontend_ops va1j5jf8007s_ops = {
        .info = {
-               .name = "VA1J5JF8007 ISDB-S",
+               .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",
                .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
@@ -628,28 +628,50 @@
        return 0;
 }
 
-static const u8 va1j5jf8007s_prepare_bufs[][2] = {
+static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = {
        {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
        {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
        {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
        {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
 };
 
+static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = {
+       {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a},
+       {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89},
+       {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04},
+       {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0},
+};
+
 static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)
 {
+       const u8 (*bufs)[2];
+       int size;
        u8 addr;
        u8 buf[2];
        struct i2c_msg msg;
        int i;
 
+       switch (state->config->frequency) {
+       case VA1J5JF8007S_20MHZ:
+               bufs = va1j5jf8007s_20mhz_prepare_bufs;
+               size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs);
+               break;
+       case VA1J5JF8007S_25MHZ:
+               bufs = va1j5jf8007s_25mhz_prepare_bufs;
+               size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs);
+               break;
+       default:
+               return -EINVAL;
+       }
+
        addr = state->config->demod_address;
 
        msg.addr = addr;
        msg.flags = 0;
        msg.len = 2;
        msg.buf = buf;
-       for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_prepare_bufs); i++) {
-               memcpy(buf, va1j5jf8007s_prepare_bufs[i], sizeof(buf));
+       for (i = 0; i < size; i++) {
+               memcpy(buf, bufs[i], sizeof(buf));
                if (i2c_transfer(state->adap, &msg, 1) != 1)
                        return -EREMOTEIO;
        }
diff -r 7c0b887911cf linux/drivers/media/dvb/pt1/va1j5jf8007s.h
--- a/linux/drivers/media/dvb/pt1/va1j5jf8007s.h        Mon Apr 05 22:56:43 
2010 -0400
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007s.h        Wed Apr 07 23:42:41 
2010 +0900
@@ -1,5 +1,5 @@
 /*
- * ISDB-S driver for VA1J5JF8007
+ * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranot...@zng.info>
  *
@@ -24,8 +24,14 @@
 #ifndef VA1J5JF8007S_H
 #define VA1J5JF8007S_H
 
+enum va1j5jf8007s_frequency {
+       VA1J5JF8007S_20MHZ,
+       VA1J5JF8007S_25MHZ,
+};
+
 struct va1j5jf8007s_config {
        u8 demod_address;
+       enum va1j5jf8007s_frequency frequency;
 };
 
 struct i2c_adapter;
diff -r 7c0b887911cf linux/drivers/media/dvb/pt1/va1j5jf8007t.c
--- a/linux/drivers/media/dvb/pt1/va1j5jf8007t.c        Mon Apr 05 22:56:43 
2010 -0400
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007t.c        Wed Apr 07 23:42:41 
2010 +0900
@@ -1,5 +1,5 @@
 /*
- * ISDB-T driver for VA1J5JF8007
+ * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranot...@zng.info>
  *
@@ -429,7 +429,7 @@
 
 static struct dvb_frontend_ops va1j5jf8007t_ops = {
        .info = {
-               .name = "VA1J5JF8007 ISDB-T",
+               .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",
                .type = FE_OFDM,
                .frequency_min = 90000000,
                .frequency_max = 770000000,
@@ -448,29 +448,50 @@
        .release = va1j5jf8007t_release,
 };
 
-static const u8 va1j5jf8007t_prepare_bufs[][2] = {
+static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = {
        {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
        {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
        {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
        {0xef, 0x01}
 };
 
+static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = {
+       {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83},
+       {0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c},
+       {0x77, 0x03}, {0xef, 0x01}
+};
+
 int va1j5jf8007t_prepare(struct dvb_frontend *fe)
 {
        struct va1j5jf8007t_state *state;
+       const u8 (*bufs)[2];
+       int size;
        u8 buf[2];
        struct i2c_msg msg;
        int i;
 
        state = fe->demodulator_priv;
 
+       switch (state->config->frequency) {
+       case VA1J5JF8007T_20MHZ:
+               bufs = va1j5jf8007t_20mhz_prepare_bufs;
+               size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs);
+               break;
+       case VA1J5JF8007T_25MHZ:
+               bufs = va1j5jf8007t_25mhz_prepare_bufs;
+               size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs);
+               break;
+       default:
+               return -EINVAL;
+       }
+
        msg.addr = state->config->demod_address;
        msg.flags = 0;
        msg.len = sizeof(buf);
        msg.buf = buf;
 
-       for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_prepare_bufs); i++) {
-               memcpy(buf, va1j5jf8007t_prepare_bufs[i], sizeof(buf));
+       for (i = 0; i < size; i++) {
+               memcpy(buf, bufs[i], sizeof(buf));
                if (i2c_transfer(state->adap, &msg, 1) != 1)
                        return -EREMOTEIO;
        }
diff -r 7c0b887911cf linux/drivers/media/dvb/pt1/va1j5jf8007t.h
--- a/linux/drivers/media/dvb/pt1/va1j5jf8007t.h        Mon Apr 05 22:56:43 
2010 -0400
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007t.h        Wed Apr 07 23:42:41 
2010 +0900
@@ -1,5 +1,5 @@
 /*
- * ISDB-T driver for VA1J5JF8007
+ * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
  *
  * Copyright (C) 2009 HIRANO Takahito <hiranot...@zng.info>
  *
@@ -24,8 +24,14 @@
 #ifndef VA1J5JF8007T_H
 #define VA1J5JF8007T_H
 
+enum va1j5jf8007t_frequency {
+       VA1J5JF8007T_20MHZ,
+       VA1J5JF8007T_25MHZ,
+};
+
 struct va1j5jf8007t_config {
        u8 demod_address;
+       enum va1j5jf8007t_frequency frequency;
 };
 
 struct i2c_adapter;
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to