aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/siano
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/siano')
-rw-r--r--drivers/media/dvb/siano/sms-cards.c119
-rw-r--r--drivers/media/dvb/siano/sms-cards.h13
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c78
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h36
-rw-r--r--drivers/media/dvb/siano/smsdvb.c56
-rw-r--r--drivers/media/dvb/siano/smsusb.c45
6 files changed, 344 insertions, 3 deletions
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index e98d6caf2c23..4307e4e8aa34 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -38,6 +38,16 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
{ USB_DEVICE(0x2040, 0x1801),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+ { USB_DEVICE(0x2040, 0x2000),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+ { USB_DEVICE(0x2040, 0x2009),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
+ { USB_DEVICE(0x2040, 0x200a),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+ { USB_DEVICE(0x2040, 0x2010),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+ { USB_DEVICE(0x2040, 0x2019),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
{ USB_DEVICE(0x2040, 0x5500),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5510),
@@ -96,6 +106,21 @@ static struct sms_board sms_boards[] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .led_power = 26,
+ .led_lo = 27,
+ .led_hi = 28,
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
+ .name = "Hauppauge WinTV MiniCard",
+ .type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .lna_ctrl = 29,
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
+ .name = "Hauppauge WinTV MiniCard",
+ .type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .lna_ctrl = -1,
},
};
@@ -106,3 +131,97 @@ struct sms_board *sms_get_board(int id)
return &sms_boards[id];
}
+static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
+{
+ int lvl, ret;
+ u32 gpio;
+ struct smscore_gpio_config gpioconfig = {
+ .direction = SMS_GPIO_DIRECTION_OUTPUT,
+ .pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
+ .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
+ .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST,
+ .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA,
+ };
+
+ if (pin == 0)
+ return -EINVAL;
+
+ if (pin < 0) {
+ /* inverted gpio */
+ gpio = pin * -1;
+ lvl = enable ? 0 : 1;
+ } else {
+ gpio = pin;
+ lvl = enable ? 1 : 0;
+ }
+
+ ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
+ if (ret < 0)
+ return ret;
+
+ return smscore_set_gpio(coredev, gpio, lvl);
+}
+
+int sms_board_setup(struct smscore_device_t *coredev)
+{
+ int board_id = smscore_get_board_id(coredev);
+ struct sms_board *board = sms_get_board(board_id);
+
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ /* turn off all LEDs */
+ sms_set_gpio(coredev, board->led_power, 0);
+ sms_set_gpio(coredev, board->led_hi, 0);
+ sms_set_gpio(coredev, board->led_lo, 0);
+ break;
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ /* turn off LNA */
+ sms_set_gpio(coredev, board->lna_ctrl, 0);
+ break;
+ }
+ return 0;
+}
+
+int sms_board_power(struct smscore_device_t *coredev, int onoff)
+{
+ int board_id = smscore_get_board_id(coredev);
+ struct sms_board *board = sms_get_board(board_id);
+
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ /* power LED */
+ sms_set_gpio(coredev,
+ board->led_power, onoff ? 1 : 0);
+ break;
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ /* LNA */
+ sms_set_gpio(coredev,
+ board->lna_ctrl, onoff ? 1 : 0);
+ break;
+ }
+ return 0;
+}
+
+int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
+{
+ int board_id = smscore_get_board_id(coredev);
+ struct sms_board *board = sms_get_board(board_id);
+
+ /* dont touch GPIO if LEDs are already set */
+ if (smscore_led_state(coredev, -1) == led)
+ return 0;
+
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ sms_set_gpio(coredev,
+ board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
+ sms_set_gpio(coredev,
+ board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
+
+ smscore_led_state(coredev, led);
+ break;
+ }
+ return 0;
+}
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index c8f3da6f9bc1..8e0fe9fd2610 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -32,14 +32,27 @@
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
struct sms_board {
enum sms_device_type_st type;
char *name, *fw[DEVICE_MODE_MAX];
+
+ /* gpios */
+ int led_power, led_hi, led_lo, lna_ctrl;
};
struct sms_board *sms_get_board(int id);
+int sms_board_setup(struct smscore_device_t *coredev);
+
+#define SMS_LED_OFF 0
+#define SMS_LED_LO 1
+#define SMS_LED_HI 2
+int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
+int sms_board_power(struct smscore_device_t *coredev, int onoff);
+
extern struct usb_device_id smsusb_id_table[];
#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index 6576fbb40fc6..cf613f22fb8d 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -91,6 +91,7 @@ struct smscore_device_t {
struct completion init_device_done, reload_start_done, resume_done;
int board_id;
+ int led_state;
};
void smscore_set_board_id(struct smscore_device_t *core, int id)
@@ -98,6 +99,13 @@ void smscore_set_board_id(struct smscore_device_t *core, int id)
core->board_id = id;
}
+int smscore_led_state(struct smscore_device_t *core, int led)
+{
+ if (led >= 0)
+ core->led_state = led;
+ return core->led_state;
+}
+
int smscore_get_board_id(struct smscore_device_t *core)
{
return core->board_id;
@@ -1187,6 +1195,76 @@ int smsclient_sendrequest(struct smscore_client_t *client,
}
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+ struct smscore_gpio_config *pinconfig)
+{
+ struct {
+ struct SmsMsgHdr_ST hdr;
+ u32 data[6];
+ } msg;
+
+ if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+ msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ msg.hdr.msgDstId = HIF_TASK;
+ msg.hdr.msgFlags = 0;
+ msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+ msg.hdr.msgLength = sizeof(msg);
+
+ msg.data[0] = pin;
+ msg.data[1] = pinconfig->pullupdown;
+
+ /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
+ msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
+
+ switch (pinconfig->outputdriving) {
+ case SMS_GPIO_OUTPUTDRIVING_16mA:
+ msg.data[3] = 7; /* Nova - 16mA */
+ break;
+ case SMS_GPIO_OUTPUTDRIVING_12mA:
+ msg.data[3] = 5; /* Nova - 11mA */
+ break;
+ case SMS_GPIO_OUTPUTDRIVING_8mA:
+ msg.data[3] = 3; /* Nova - 7mA */
+ break;
+ case SMS_GPIO_OUTPUTDRIVING_4mA:
+ default:
+ msg.data[3] = 2; /* Nova - 4mA */
+ break;
+ }
+
+ msg.data[4] = pinconfig->direction;
+ msg.data[5] = 0;
+ } else /* TODO: SMS_DEVICE_FAMILY1 */
+ return -EINVAL;
+
+ return coredev->sendrequest_handler(coredev->context,
+ &msg, sizeof(msg));
+}
+
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
+{
+ struct {
+ struct SmsMsgHdr_ST hdr;
+ u32 data[3];
+ } msg;
+
+ if (pin > MAX_GPIO_PIN_NUMBER)
+ return -EINVAL;
+
+ msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ msg.hdr.msgDstId = HIF_TASK;
+ msg.hdr.msgFlags = 0;
+ msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+ msg.hdr.msgLength = sizeof(msg);
+
+ msg.data[0] = pin;
+ msg.data[1] = level ? 1 : 0;
+ msg.data[2] = 0;
+
+ return coredev->sendrequest_handler(coredev->context,
+ &msg, sizeof(msg));
+}
+
static int __init smscore_module_init(void)
{
int rc = 0;
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index 8d973f726fb8..760e233fcbc5 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -186,6 +186,8 @@ struct smsclient_params_t {
#define MSG_SW_RELOAD_EXEC_REQ 704
#define MSG_SW_RELOAD_EXEC_RES 705
#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
+#define MSG_SMS_GPIO_CONFIG_EX_REQ 712
+#define MSG_SMS_GPIO_CONFIG_EX_RES 713
#define MSG_SMS_ISDBT_TUNE_REQ 776
#define MSG_SMS_ISDBT_TUNE_RES 777
@@ -341,6 +343,32 @@ struct SmsMsgStatisticsInfo_ST {
};
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT 0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+ u8 direction;
+
+#define SMS_GPIO_PULLUPDOWN_NONE 0
+#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
+#define SMS_GPIO_PULLUPDOWN_PULLUP 2
+#define SMS_GPIO_PULLUPDOWN_KEEPER 3
+ u8 pullupdown;
+
+#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0
+#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
+ u8 inputcharacteristics;
+
+#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
+#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
+ u8 outputslewrate;
+
+#define SMS_GPIO_OUTPUTDRIVING_4mA 0
+#define SMS_GPIO_OUTPUTDRIVING_8mA 1
+#define SMS_GPIO_OUTPUTDRIVING_12mA 2
+#define SMS_GPIO_OUTPUTDRIVING_16mA 3
+ u8 outputdriving;
+};
+
struct smsdvb_client_t {
struct list_head entry;
@@ -353,7 +381,7 @@ struct smsdvb_client_t {
struct dvb_frontend frontend;
fe_status_t fe_status;
- int fe_ber, fe_snr, fe_signal_strength;
+ int fe_ber, fe_snr, fe_unc, fe_signal_strength;
struct completion tune_done, stat_done;
@@ -396,9 +424,15 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
extern void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb);
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+ struct smscore_gpio_config *pinconfig);
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
+
void smscore_set_board_id(struct smscore_device_t *core, int id);
int smscore_get_board_id(struct smscore_device_t *core);
+int smscore_led_state(struct smscore_device_t *core, int led);
+
/* smsdvb.c */
int smsdvb_register(void);
void smsdvb_unregister(void);
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 8d490e133f35..2da953a4f4f5 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -60,6 +60,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
client->fe_snr = p->Stat.SNR;
client->fe_ber = p->Stat.BER;
+ client->fe_unc = p->Stat.BERErrorCount;
if (p->Stat.InBandPwr < -95)
client->fe_signal_strength = 0;
@@ -72,6 +73,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
client->fe_status = 0;
client->fe_snr =
client->fe_ber =
+ client->fe_unc =
client->fe_signal_strength = 0;
}
@@ -165,8 +167,18 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
DVBT_BDA_CONTROL_MSG_ID,
HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
- return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
- &client->stat_done);
+ int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->stat_done);
+ if (ret < 0)
+ return ret;
+
+ if (client->fe_status & FE_HAS_LOCK)
+ sms_board_led_feedback(client->coredev,
+ (client->fe_unc == 0) ?
+ SMS_LED_HI : SMS_LED_LO);
+ else
+ sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+ return ret;
}
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -217,6 +229,18 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
return rc;
}
+static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int rc = smsdvb_send_statistics_request(client);
+
+ if (!rc)
+ *ucblocks = client->fe_unc;
+
+ return rc;
+}
+
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
@@ -273,6 +297,28 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe,
/* todo: */
memcpy(fep, &client->fe_params,
sizeof(struct dvb_frontend_parameters));
+
+ return 0;
+}
+
+static int smsdvb_init(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_board_power(client->coredev, 1);
+
+ return 0;
+}
+
+static int smsdvb_sleep(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+ sms_board_power(client->coredev, 0);
+
return 0;
}
@@ -308,6 +354,10 @@ static struct dvb_frontend_ops smsdvb_fe_ops = {
.read_ber = smsdvb_read_ber,
.read_signal_strength = smsdvb_read_signal_strength,
.read_snr = smsdvb_read_snr,
+ .read_ucblocks = smsdvb_read_ucblocks,
+
+ .init = smsdvb_init,
+ .sleep = smsdvb_sleep,
};
static int smsdvb_hotplug(struct smscore_device_t *coredev,
@@ -402,6 +452,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
sms_info("success");
+ sms_board_setup(coredev);
+
return 0;
client_error:
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index 87a3c24454b9..5d7ca3417719 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -432,11 +432,56 @@ static void smsusb_disconnect(struct usb_interface *intf)
smsusb_term_device(intf);
}
+static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ struct smsusb_device_t *dev =
+ (struct smsusb_device_t *)usb_get_intfdata(intf);
+ printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event);
+ smsusb_stop_streaming(dev);
+ return 0;
+}
+
+static int smsusb_resume(struct usb_interface *intf)
+{
+ int rc, i;
+ struct smsusb_device_t *dev =
+ (struct smsusb_device_t *)usb_get_intfdata(intf);
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ printk(KERN_INFO "%s Entering.\n", __func__);
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+
+ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
+ printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
+ intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
+ intf->cur_altsetting->endpoint[i].desc.bmAttributes,
+ intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+
+ if (intf->num_altsetting > 0) {
+ rc = usb_set_interface(udev,
+ intf->cur_altsetting->desc.
+ bInterfaceNumber, 0);
+ if (rc < 0) {
+ printk(KERN_INFO
+ "%s usb_set_interface failed, rc %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ smsusb_start_streaming(dev);
+ return 0;
+}
+
static struct usb_driver smsusb_driver = {
.name = "sms1xxx",
.probe = smsusb_probe,
.disconnect = smsusb_disconnect,
.id_table = smsusb_id_table,
+
+ .suspend = smsusb_suspend,
+ .resume = smsusb_resume,
};
int smsusb_register(void)