Loading drivers/media/dvb/pt1/pt1.c +211 −60 Original line number Diff line number Diff line /* * driver for Earthsoft PT1 * driver for Earthsoft PT1/PT2 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading Loading @@ -77,6 +77,10 @@ struct pt1 { 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 { Loading @@ -95,6 +99,11 @@ struct pt1_adapter { 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...) \ Loading Loading @@ -219,8 +228,10 @@ static int pt1_do_enable_ram(struct pt1 *pt1) 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; Loading Loading @@ -485,33 +496,47 @@ static int pt1_stop_feed(struct dvb_demux_feed *feed) } static void pt1_set_power(struct pt1 *pt1, int power, int lnb, int reset) { pt1_write_reg(pt1, 1, power | lnb << 1 | !reset << 3); } static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) pt1_update_power(struct pt1 *pt1) { int bits; int i; struct pt1_adapter *adap; int lnb; adap = container_of(fe->dvb, struct pt1_adapter, adap); static const int sleep_bits[] = { 1 << 4, 1 << 6 | 1 << 7, 1 << 5, 1 << 6 | 1 << 8, }; switch (voltage) { 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 */ lnb = 2; bits |= 1 << 1; break; case SEC_VOLTAGE_18: /* actually 15V */ lnb = 3; break; case SEC_VOLTAGE_OFF: lnb = 0; bits |= 1 << 1 | 1 << 2; break; default: return -EINVAL; break; } pt1_set_power(adap->pt1, 1, lnb, 0); /* 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; adap = container_of(fe->dvb, struct pt1_adapter, adap); adap->voltage = voltage; pt1_update_power(adap->pt1); if (adap->orig_set_voltage) return adap->orig_set_voltage(fe, voltage); Loading @@ -519,9 +544,37 @@ static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) 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); Loading @@ -534,7 +587,7 @@ static void pt1_free_adapter(struct pt1_adapter *adap) 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; Loading @@ -551,8 +604,8 @@ pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe) 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) { Loading Loading @@ -593,17 +646,8 @@ pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe) 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: Loading @@ -623,6 +667,62 @@ static void pt1_cleanup_adapters(struct pt1 *pt1) 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; Loading @@ -630,29 +730,63 @@ struct pt1_config { 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); Loading Loading @@ -681,11 +815,9 @@ static int pt1_init_adapters(struct pt1 *pt1) } 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; Loading @@ -695,7 +827,7 @@ static int pt1_init_adapters(struct pt1 *pt1) fe[i]->ops.release(fe[i]); while (j--) pt1_free_adapter(pt1->adaps[j]); dvb_unregister_frontend(fe[j]); return ret; } Loading Loading @@ -890,9 +1022,12 @@ static void __devexit pt1_remove(struct pci_dev *pdev) kthread_stop(pt1->kthread); pt1_cleanup_tables(pt1); pt1_cleanup_adapters(pt1); pt1_cleanup_frontends(pt1); pt1_disable_ram(pt1); pt1_set_power(pt1, 0, 0, 1); pt1->power = 0; pt1->reset = 1; pt1_update_power(pt1); pt1_cleanup_adapters(pt1); i2c_del_adapter(&pt1->i2c_adap); pci_set_drvdata(pdev, NULL); kfree(pt1); Loading Loading @@ -936,10 +1071,21 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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; Loading @@ -948,9 +1094,7 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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); Loading Loading @@ -979,19 +1123,21 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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)) { Loading @@ -1004,11 +1150,15 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_pt1_cleanup_tables: pt1_cleanup_tables(pt1); err_pt1_cleanup_adapters: pt1_cleanup_adapters(pt1); err_pt1_cleanup_frontends: pt1_cleanup_frontends(pt1); err_pt1_disable_ram: pt1_disable_ram(pt1); pt1_set_power(pt1, 0, 0, 1); pt1->power = 0; pt1->reset = 1; pt1_update_power(pt1); err_pt1_cleanup_adapters: pt1_cleanup_adapters(pt1); err_i2c_del_adapter: i2c_del_adapter(i2c_adap); err_kfree: Loading @@ -1027,6 +1177,7 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static struct pci_device_id pt1_id_table[] = { { PCI_DEVICE(0x10ee, 0x211a) }, { PCI_DEVICE(0x10ee, 0x222a) }, { }, }; MODULE_DEVICE_TABLE(pci, pt1_id_table); Loading Loading @@ -1054,5 +1205,5 @@ module_init(pt1_init); module_exit(pt1_cleanup); MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>"); MODULE_DESCRIPTION("Earthsoft PT1 Driver"); MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); MODULE_LICENSE("GPL"); drivers/media/dvb/pt1/va1j5jf8007s.c +27 −5 Original line number Diff line number Diff line /* * ISDB-S driver for VA1J5JF8007 * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading Loading @@ -580,7 +580,7 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe) 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, Loading Loading @@ -628,28 +628,50 @@ static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) 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; } Loading drivers/media/dvb/pt1/va1j5jf8007s.h +7 −1 Original line number Diff line number Diff line /* * ISDB-S driver for VA1J5JF8007 * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading @@ -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; Loading drivers/media/dvb/pt1/va1j5jf8007t.c +26 −5 Original line number Diff line number Diff line /* * ISDB-T driver for VA1J5JF8007 * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading Loading @@ -429,7 +429,7 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe) 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, Loading @@ -448,29 +448,50 @@ static struct dvb_frontend_ops va1j5jf8007t_ops = { .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; } Loading drivers/media/dvb/pt1/va1j5jf8007t.h +7 −1 Original line number Diff line number Diff line /* * ISDB-T driver for VA1J5JF8007 * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading @@ -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; Loading Loading
drivers/media/dvb/pt1/pt1.c +211 −60 Original line number Diff line number Diff line /* * driver for Earthsoft PT1 * driver for Earthsoft PT1/PT2 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading Loading @@ -77,6 +77,10 @@ struct pt1 { 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 { Loading @@ -95,6 +99,11 @@ struct pt1_adapter { 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...) \ Loading Loading @@ -219,8 +228,10 @@ static int pt1_do_enable_ram(struct pt1 *pt1) 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; Loading Loading @@ -485,33 +496,47 @@ static int pt1_stop_feed(struct dvb_demux_feed *feed) } static void pt1_set_power(struct pt1 *pt1, int power, int lnb, int reset) { pt1_write_reg(pt1, 1, power | lnb << 1 | !reset << 3); } static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) pt1_update_power(struct pt1 *pt1) { int bits; int i; struct pt1_adapter *adap; int lnb; adap = container_of(fe->dvb, struct pt1_adapter, adap); static const int sleep_bits[] = { 1 << 4, 1 << 6 | 1 << 7, 1 << 5, 1 << 6 | 1 << 8, }; switch (voltage) { 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 */ lnb = 2; bits |= 1 << 1; break; case SEC_VOLTAGE_18: /* actually 15V */ lnb = 3; break; case SEC_VOLTAGE_OFF: lnb = 0; bits |= 1 << 1 | 1 << 2; break; default: return -EINVAL; break; } pt1_set_power(adap->pt1, 1, lnb, 0); /* 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; adap = container_of(fe->dvb, struct pt1_adapter, adap); adap->voltage = voltage; pt1_update_power(adap->pt1); if (adap->orig_set_voltage) return adap->orig_set_voltage(fe, voltage); Loading @@ -519,9 +544,37 @@ static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) 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); Loading @@ -534,7 +587,7 @@ static void pt1_free_adapter(struct pt1_adapter *adap) 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; Loading @@ -551,8 +604,8 @@ pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe) 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) { Loading Loading @@ -593,17 +646,8 @@ pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe) 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: Loading @@ -623,6 +667,62 @@ static void pt1_cleanup_adapters(struct pt1 *pt1) 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; Loading @@ -630,29 +730,63 @@ struct pt1_config { 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); Loading Loading @@ -681,11 +815,9 @@ static int pt1_init_adapters(struct pt1 *pt1) } 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; Loading @@ -695,7 +827,7 @@ static int pt1_init_adapters(struct pt1 *pt1) fe[i]->ops.release(fe[i]); while (j--) pt1_free_adapter(pt1->adaps[j]); dvb_unregister_frontend(fe[j]); return ret; } Loading Loading @@ -890,9 +1022,12 @@ static void __devexit pt1_remove(struct pci_dev *pdev) kthread_stop(pt1->kthread); pt1_cleanup_tables(pt1); pt1_cleanup_adapters(pt1); pt1_cleanup_frontends(pt1); pt1_disable_ram(pt1); pt1_set_power(pt1, 0, 0, 1); pt1->power = 0; pt1->reset = 1; pt1_update_power(pt1); pt1_cleanup_adapters(pt1); i2c_del_adapter(&pt1->i2c_adap); pci_set_drvdata(pdev, NULL); kfree(pt1); Loading Loading @@ -936,10 +1071,21 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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; Loading @@ -948,9 +1094,7 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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); Loading Loading @@ -979,19 +1123,21 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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)) { Loading @@ -1004,11 +1150,15 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_pt1_cleanup_tables: pt1_cleanup_tables(pt1); err_pt1_cleanup_adapters: pt1_cleanup_adapters(pt1); err_pt1_cleanup_frontends: pt1_cleanup_frontends(pt1); err_pt1_disable_ram: pt1_disable_ram(pt1); pt1_set_power(pt1, 0, 0, 1); pt1->power = 0; pt1->reset = 1; pt1_update_power(pt1); err_pt1_cleanup_adapters: pt1_cleanup_adapters(pt1); err_i2c_del_adapter: i2c_del_adapter(i2c_adap); err_kfree: Loading @@ -1027,6 +1177,7 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static struct pci_device_id pt1_id_table[] = { { PCI_DEVICE(0x10ee, 0x211a) }, { PCI_DEVICE(0x10ee, 0x222a) }, { }, }; MODULE_DEVICE_TABLE(pci, pt1_id_table); Loading Loading @@ -1054,5 +1205,5 @@ module_init(pt1_init); module_exit(pt1_cleanup); MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>"); MODULE_DESCRIPTION("Earthsoft PT1 Driver"); MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); MODULE_LICENSE("GPL");
drivers/media/dvb/pt1/va1j5jf8007s.c +27 −5 Original line number Diff line number Diff line /* * ISDB-S driver for VA1J5JF8007 * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading Loading @@ -580,7 +580,7 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe) 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, Loading Loading @@ -628,28 +628,50 @@ static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) 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; } Loading
drivers/media/dvb/pt1/va1j5jf8007s.h +7 −1 Original line number Diff line number Diff line /* * ISDB-S driver for VA1J5JF8007 * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading @@ -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; Loading
drivers/media/dvb/pt1/va1j5jf8007t.c +26 −5 Original line number Diff line number Diff line /* * ISDB-T driver for VA1J5JF8007 * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading Loading @@ -429,7 +429,7 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe) 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, Loading @@ -448,29 +448,50 @@ static struct dvb_frontend_ops va1j5jf8007t_ops = { .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; } Loading
drivers/media/dvb/pt1/va1j5jf8007t.h +7 −1 Original line number Diff line number Diff line /* * ISDB-T driver for VA1J5JF8007 * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 * * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> * Loading @@ -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; Loading