diff options
Diffstat (limited to 'drivers/media/radio/wl128x')
| -rw-r--r-- | drivers/media/radio/wl128x/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv.h | 9 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_common.c | 89 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_common.h | 28 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_rx.c | 88 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_rx.h | 50 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_tx.c | 61 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_tx.h | 20 | ||||
| -rw-r--r-- | drivers/media/radio/wl128x/fmdrv_v4l2.c | 87 |
9 files changed, 241 insertions, 195 deletions
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index 749f67b192e..f359be7e9dd 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -4,8 +4,8 @@ menu "Texas Instruments WL128x FM driver (ST based)" config RADIO_WL128X tristate "Texas Instruments WL128x FM Radio" - depends on VIDEO_V4L2 && RFKILL - select TI_ST + depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY + select TI_ST if NET help Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h index 1a45a5d847b..a587c9bac93 100644 --- a/drivers/media/radio/wl128x/fmdrv.h +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -28,14 +28,12 @@ #include <sound/core.h> #include <sound/initval.h> #include <linux/timer.h> -#include <linux/version.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#define FM_DRV_VERSION "0.10" -/* Should match with FM_DRV_VERSION */ -#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1) +#define FM_DRV_VERSION "0.1.1" #define FM_DRV_NAME "ti_fmdrv" #define FM_DRV_CARD_SHORT_NAME "TI FM Radio" #define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio" @@ -63,7 +61,7 @@ #define fmdbg(format, ...) \ printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__) #else /* DEBUG */ -#define fmdbg(format, ...) +#define fmdbg(format, ...) do {} while(0) #endif enum { FM_MODE_OFF, @@ -205,6 +203,7 @@ struct fmtx_data { /* FM driver operation structure */ struct fmdev { struct video_device *radio_dev; /* V4L2 video device pointer */ + struct v4l2_device v4l2_dev; /* V4L2 top level struct */ struct snd_card *card; /* Card which holds FM mixer controls */ u16 asci_id; spinlock_t rds_buff_lock; /* To protect access to RDS buffer */ diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 5991ab60303..4b2e9e8298e 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -175,7 +175,7 @@ static int_handler_prototype int_handler_table[] = { fm_irq_handle_intmsk_cmd_resp }; -long (*g_st_write) (struct sk_buff *skb); +static long (*g_st_write) (struct sk_buff *skb); static struct completion wait_for_fmdrv_reg_comp; static inline void fm_irq_call(struct fmdev *fmdev) @@ -387,7 +387,7 @@ static void send_tasklet(unsigned long arg) * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for * transmission */ -static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, +static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, int payload_len, struct completion *wait_completion) { struct sk_buff *skb; @@ -456,13 +456,13 @@ static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, } /* Sends FM Channel-8 command to the chip and waits for the response */ -u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, +int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, unsigned int payload_len, void *response, int *response_len) { struct sk_buff *skb; struct fm_event_msg_hdr *evt_hdr; unsigned long flags; - u32 ret; + int ret; init_completion(&fmdev->maintask_comp); ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, @@ -470,8 +470,8 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, if (ret) return ret; - ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT)) { fmerr("Timeout(%d sec),didn't get reg" "completion signal from RX tasklet\n", jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); @@ -508,7 +508,7 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, } /* --- Helper functions used in FM interrupt handlers ---*/ -static inline u32 check_cmdresp_status(struct fmdev *fmdev, +static inline int check_cmdresp_status(struct fmdev *fmdev, struct sk_buff **skb) { struct fm_event_msg_hdr *fm_evt_hdr; @@ -715,7 +715,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) struct fm_rdsdata_format rds_fmt; struct fm_rds *rds = &fmdev->rx.rds; unsigned long group_idx, flags; - u8 *rds_data, meta_data, tmpbuf[3]; + u8 *rds_data, meta_data, tmpbuf[FM_RDS_BLK_SIZE]; u8 type, blk_idx; u16 cur_picode; u32 rds_len; @@ -742,7 +742,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) break; - if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { + if (blk_idx > FM_RDS_BLK_IDX_D) { fmdbg("Block sequence mismatch\n"); rds->last_blk_idx = -1; break; @@ -1058,7 +1058,7 @@ static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) } /* Returns availability of RDS data in internel buffer */ -u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, +int fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, struct poll_table_struct *pts) { poll_wait(file, &fmdev->rx.rds.read_queue, pts); @@ -1069,10 +1069,11 @@ u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, } /* Copies RDS data from internal buffer to user buffer */ -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, +int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, u8 __user *buf, size_t count) { u32 block_count; + u8 tmpbuf[FM_RDS_BLK_SIZE]; unsigned long flags; int ret; @@ -1087,33 +1088,36 @@ u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, } /* Calculate block count from byte count */ - count /= 3; + count /= FM_RDS_BLK_SIZE; block_count = 0; ret = 0; - spin_lock_irqsave(&fmdev->rds_buff_lock, flags); - while (block_count < count) { - if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) - break; + spin_lock_irqsave(&fmdev->rds_buff_lock, flags); - if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], - FM_RDS_BLK_SIZE)) + if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); break; - + } + memcpy(tmpbuf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], + FM_RDS_BLK_SIZE); fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) fmdev->rx.rds.rd_idx = 0; + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); + + if (copy_to_user(buf, tmpbuf, FM_RDS_BLK_SIZE)) + break; + block_count++; buf += FM_RDS_BLK_SIZE; ret += FM_RDS_BLK_SIZE; } - spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); return ret; } -u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) +int fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1127,7 +1131,7 @@ u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) } } -u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) +int fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) { if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { fmerr("RX frequency is not set\n"); @@ -1153,7 +1157,7 @@ u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) } -u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) +int fmc_set_region(struct fmdev *fmdev, u8 region_to_set) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1167,7 +1171,7 @@ u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) } } -u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1181,7 +1185,7 @@ u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } } -u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1195,7 +1199,7 @@ u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) } } -u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1210,10 +1214,10 @@ u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) } /* Sends power off command to the chip */ -static u32 fm_power_down(struct fmdev *fmdev) +static int fm_power_down(struct fmdev *fmdev) { u16 payload; - u32 ret; + int ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmerr("FM core is not ready\n"); @@ -1234,7 +1238,7 @@ static u32 fm_power_down(struct fmdev *fmdev) } /* Reads init command from FM firmware file and loads to the chip */ -static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) +static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) { const struct firmware *fw_entry; struct bts_header *fw_header; @@ -1299,7 +1303,7 @@ rel_fw: } /* Loads default RX configuration to the chip */ -static u32 load_default_rx_configuration(struct fmdev *fmdev) +static int load_default_rx_configuration(struct fmdev *fmdev) { int ret; @@ -1311,7 +1315,7 @@ static u32 load_default_rx_configuration(struct fmdev *fmdev) } /* Does FM power on sequence */ -static u32 fm_power_up(struct fmdev *fmdev, u8 mode) +static int fm_power_up(struct fmdev *fmdev, u8 mode) { u16 payload, asic_id, asic_ver; int resp_len, ret; @@ -1374,7 +1378,7 @@ rel: } /* Set FM Modes(TX, RX, OFF) */ -u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) +int fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) { int ret = 0; @@ -1427,7 +1431,7 @@ u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) } /* Returns current FM mode (TX, RX, OFF) */ -u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) +int fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) { if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmerr("FM core is not ready\n"); @@ -1483,10 +1487,10 @@ static void fm_st_reg_comp_cb(void *arg, char data) * This function will be called from FM V4L2 open function. * Register with ST driver and initialize driver data. */ -u32 fmc_prepare(struct fmdev *fmdev) +int fmc_prepare(struct fmdev *fmdev) { static struct st_proto_s fm_st_proto; - u32 ret; + int ret; if (test_bit(FM_CORE_READY, &fmdev->flag)) { fmdbg("FM Core is already up\n"); @@ -1512,10 +1516,8 @@ u32 fmc_prepare(struct fmdev *fmdev) fmdev->streg_cbdata = -EINPROGRESS; fmdbg("%s waiting for ST reg completion signal\n", __func__); - ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, - FM_ST_REG_TIMEOUT); - - if (!ret) { + if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, + FM_ST_REG_TIMEOUT)) { fmerr("Timeout(%d sec), didn't get reg " "completion signal from ST\n", jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); @@ -1565,8 +1567,7 @@ u32 fmc_prepare(struct fmdev *fmdev) fmdev->irq_info.mask = FM_MAL_EVENT; /* Region info */ - memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region], - sizeof(struct region_info)); + fmdev->rx.region = region_configs[default_radio_region]; fmdev->rx.mute_mode = FM_MUTE_OFF; fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF; @@ -1589,10 +1590,10 @@ u32 fmc_prepare(struct fmdev *fmdev) * This function will be called from FM V4L2 release function. * Unregister from ST driver. */ -u32 fmc_release(struct fmdev *fmdev) +int fmc_release(struct fmdev *fmdev) { static struct st_proto_s fm_st_proto; - u32 ret; + int ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmdbg("FM Core is already down\n"); @@ -1631,7 +1632,7 @@ u32 fmc_release(struct fmdev *fmdev) static int __init fm_drv_init(void) { struct fmdev *fmdev = NULL; - u32 ret = -ENOMEM; + int ret = -ENOMEM; fmdbg("FM driver version %s\n", FM_DRV_VERSION); diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h index aee243bb663..d9b9c6cf83b 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.h +++ b/drivers/media/radio/wl128x/fmdrv_common.h @@ -368,27 +368,27 @@ struct fm_event_msg_hdr { #define FM_TX_ANT_IMP_500 2 /* Functions exported by FM common sub-module */ -u32 fmc_prepare(struct fmdev *); -u32 fmc_release(struct fmdev *); +int fmc_prepare(struct fmdev *); +int fmc_release(struct fmdev *); void fmc_update_region_info(struct fmdev *, u8); -u32 fmc_send_cmd(struct fmdev *, u8, u16, +int fmc_send_cmd(struct fmdev *, u8, u16, void *, unsigned int, void *, int *); -u32 fmc_is_rds_data_available(struct fmdev *, struct file *, +int fmc_is_rds_data_available(struct fmdev *, struct file *, struct poll_table_struct *); -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, +int fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, u8 __user *, size_t); -u32 fmc_set_freq(struct fmdev *, u32); -u32 fmc_set_mode(struct fmdev *, u8); -u32 fmc_set_region(struct fmdev *, u8); -u32 fmc_set_mute_mode(struct fmdev *, u8); -u32 fmc_set_stereo_mono(struct fmdev *, u16); -u32 fmc_set_rds_mode(struct fmdev *, u8); +int fmc_set_freq(struct fmdev *, u32); +int fmc_set_mode(struct fmdev *, u8); +int fmc_set_region(struct fmdev *, u8); +int fmc_set_mute_mode(struct fmdev *, u8); +int fmc_set_stereo_mono(struct fmdev *, u16); +int fmc_set_rds_mode(struct fmdev *, u8); -u32 fmc_get_freq(struct fmdev *, u32 *); -u32 fmc_get_region(struct fmdev *, u8 *); -u32 fmc_get_mode(struct fmdev *, u8 *); +int fmc_get_freq(struct fmdev *, u32 *); +int fmc_get_region(struct fmdev *, u8 *); +int fmc_get_mode(struct fmdev *, u8 *); /* * channel spacing diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index ec529b55b04..ebf09a3927d 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -43,12 +43,13 @@ void fm_rx_reset_station_info(struct fmdev *fmdev) fmdev->rx.stat_info.af_list_max = 0; } -u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) +int fm_rx_set_freq(struct fmdev *fmdev, u32 freq) { unsigned long timeleft; u16 payload, curr_frq, intr_flag; u32 curr_frq_in_khz; - u32 ret, resp_len; + u32 resp_len; + int ret; if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { fmerr("Invalid frequency %d\n", freq); @@ -141,10 +142,10 @@ exit: return ret; } -static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) +static int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) { u16 payload; - u32 ret; + int ret; if (spacing > 0 && spacing <= 50000) spacing = FM_CHANNEL_SPACING_50KHZ; @@ -165,7 +166,7 @@ static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) return ret; } -u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, +int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, u32 wrap_around, u32 spacing) { u32 resp_len; @@ -173,7 +174,7 @@ u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, u16 payload, int_reason, intr_flag; u16 offset, space_idx; unsigned long timeleft; - u32 ret; + int ret; /* Set channel spacing */ ret = fm_rx_set_channel_spacing(fmdev, spacing); @@ -250,7 +251,7 @@ again: if (!timeleft) { fmerr("Timeout(%d sec),didn't get tune ended int\n", jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); - return -ETIMEDOUT; + return -ENODATA; } int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); @@ -296,15 +297,15 @@ again: return ret; } -u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) +int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; - if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) { + if (vol_to_set > FM_RX_VOLUME_MAX) { fmerr("Volume is not within(%d-%d) range\n", FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); return -EINVAL; @@ -322,7 +323,7 @@ u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) } /* Get volume */ -u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) +int fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -338,7 +339,7 @@ u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) } /* To get current band's bottom and top frequency */ -u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) +int fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) { if (bot_freq != NULL) *bot_freq = fmdev->rx.region.bot_freq; @@ -356,11 +357,11 @@ void fm_rx_get_region(struct fmdev *fmdev, u8 *region) } /* Sets band (0-Europe/US; 1-Japan) */ -u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) +int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) { u16 payload; u32 new_frq = 0; - u32 ret; + int ret; if (region_to_set != FM_BAND_EUROPE_US && region_to_set != FM_BAND_JAPAN) { @@ -399,7 +400,7 @@ u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) } /* Reads current mute mode (Mute Off/On/Attenuate)*/ -u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) +int fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -414,10 +415,10 @@ u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) return 0; } -static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) +static int fm_config_rx_mute_reg(struct fmdev *fmdev) { u16 payload, muteval; - u32 ret; + int ret; muteval = 0; switch (fmdev->rx.mute_mode) { @@ -448,10 +449,10 @@ static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) } /* Configures mute mode (Mute Off/On/Attenuate) */ -u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { u8 org_state; - u32 ret; + int ret; if (fmdev->rx.mute_mode == mute_mode_toset) return 0; @@ -469,7 +470,7 @@ u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } /* Gets RF dependent soft mute mode enable/disable status */ -u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) +int fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -485,10 +486,10 @@ u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) } /* Sets RF dependent soft mute mode */ -u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) +int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) { u8 org_state; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -514,11 +515,11 @@ u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) } /* Returns the signal strength level of current channel */ -u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) +int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) { u16 curr_rssi_lel; u32 resp_len; - u32 ret; + int ret; if (rssilvl == NULL) { fmerr("Invalid memory\n"); @@ -539,10 +540,10 @@ u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) * Sets the signal strength level that once reached * will stop the auto search process */ -u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) +int fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) { u16 payload; - u32 ret; + int ret; if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { @@ -561,7 +562,7 @@ u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) } /* Returns current RX RSSI threshold value */ -u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) +int fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -577,10 +578,10 @@ u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) } /* Sets RX stereo/mono modes */ -u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { fmerr("Invalid mode\n"); @@ -605,10 +606,11 @@ u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) } /* Gets current RX stereo/mono mode */ -u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) +int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) { u16 curr_mode; - u32 ret, resp_len; + u32 resp_len; + int ret; if (mode == NULL) { fmerr("Invalid memory\n"); @@ -626,10 +628,10 @@ u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) } /* Choose RX de-emphasis filter mode (50us/75us) */ -u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) +int fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -652,7 +654,7 @@ u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) } /* Gets current RX de-emphasis filter mode */ -u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) +int fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -668,10 +670,10 @@ u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) } /* Enable/Disable RX RDS */ -u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { u16 payload; - u32 ret; + int ret; if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { fmerr("Invalid rds option\n"); @@ -743,7 +745,7 @@ u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) } /* Returns current RX RDS enable/disable status */ -u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) +int fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -759,10 +761,10 @@ u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) } /* Sets RDS operation mode (RDS/RDBS) */ -u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) +int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -784,7 +786,7 @@ u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) } /* Returns current RDS operation mode */ -u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) +int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -800,10 +802,10 @@ u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) } /* Configures Alternate Frequency switch mode */ -u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) +int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -831,7 +833,7 @@ u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) } /* Returns Alternate Frequency switch status */ -u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) +int fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h index 329e62f6be7..32add81f8d8 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.h +++ b/drivers/media/radio/wl128x/fmdrv_rx.h @@ -22,38 +22,38 @@ #ifndef _FMDRV_RX_H #define _FMDRV_RX_H -u32 fm_rx_set_freq(struct fmdev *, u32); -u32 fm_rx_set_mute_mode(struct fmdev *, u8); -u32 fm_rx_set_stereo_mono(struct fmdev *, u16); -u32 fm_rx_set_rds_mode(struct fmdev *, u8); -u32 fm_rx_set_rds_system(struct fmdev *, u8); -u32 fm_rx_set_volume(struct fmdev *, u16); -u32 fm_rx_set_rssi_threshold(struct fmdev *, short); -u32 fm_rx_set_region(struct fmdev *, u8); -u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8); -u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16); -u32 fm_rx_set_af_switch(struct fmdev *, u8); +int fm_rx_set_freq(struct fmdev *, u32); +int fm_rx_set_mute_mode(struct fmdev *, u8); +int fm_rx_set_stereo_mono(struct fmdev *, u16); +int fm_rx_set_rds_mode(struct fmdev *, u8); +int fm_rx_set_rds_system(struct fmdev *, u8); +int fm_rx_set_volume(struct fmdev *, u16); +int fm_rx_set_rssi_threshold(struct fmdev *, short); +int fm_rx_set_region(struct fmdev *, u8); +int fm_rx_set_rfdepend_softmute(struct fmdev *, u8); +int fm_rx_set_deemphasis_mode(struct fmdev *, u16); +int fm_rx_set_af_switch(struct fmdev *, u8); void fm_rx_reset_rds_cache(struct fmdev *); void fm_rx_reset_station_info(struct fmdev *); -u32 fm_rx_seek(struct fmdev *, u32, u32, u32); +int fm_rx_seek(struct fmdev *, u32, u32, u32); -u32 fm_rx_get_rds_mode(struct fmdev *, u8 *); -u32 fm_rx_get_rds_system(struct fmdev *, u8 *); -u32 fm_rx_get_mute_mode(struct fmdev *, u8 *); -u32 fm_rx_get_volume(struct fmdev *, u16 *); -u32 fm_rx_get_band_freq_range(struct fmdev *, +int fm_rx_get_rds_mode(struct fmdev *, u8 *); +int fm_rx_get_rds_system(struct fmdev *, u8 *); +int fm_rx_get_mute_mode(struct fmdev *, u8 *); +int fm_rx_get_volume(struct fmdev *, u16 *); +int fm_rx_get_band_freq_range(struct fmdev *, u32 *, u32 *); -u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_level(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_threshold(struct fmdev *, short *); -u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); -u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *); -u32 fm_rx_get_af_switch(struct fmdev *, u8 *); +int fm_rx_get_stereo_mono(struct fmdev *, u16 *); +int fm_rx_get_rssi_level(struct fmdev *, u16 *); +int fm_rx_get_rssi_threshold(struct fmdev *, short *); +int fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); +int fm_rx_get_deemph_mode(struct fmdev *, u16 *); +int fm_rx_get_af_switch(struct fmdev *, u8 *); void fm_rx_get_region(struct fmdev *, u8 *); -u32 fm_rx_set_chanl_spacing(struct fmdev *, u8); -u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *); +int fm_rx_set_chanl_spacing(struct fmdev *, u8); +int fm_rx_get_chanl_spacing(struct fmdev *, u8 *); #endif diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c index be54068b56a..6ea33e09d63 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.c +++ b/drivers/media/radio/wl128x/fmdrv_tx.c @@ -24,10 +24,10 @@ #include "fmdrv_common.h" #include "fmdrv_tx.h" -u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (fmdev->tx_data.aud_mode == mode) return 0; @@ -46,10 +46,10 @@ u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) return ret; } -static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) +static int set_rds_text(struct fmdev *fmdev, u8 *rds_text) { u16 payload; - u32 ret; + int ret; ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, strlen(rds_text), NULL, NULL); @@ -66,10 +66,10 @@ static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) return 0; } -static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) +static int set_rds_data_mode(struct fmdev *fmdev, u8 mode) { u16 payload; - u32 ret; + int ret; /* Setting unique PI TODO: how unique? */ payload = (u16)0xcafe; @@ -89,10 +89,10 @@ static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) return 0; } -static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) +static int set_rds_len(struct fmdev *fmdev, u8 type, u16 len) { u16 payload; - u32 ret; + int ret; len |= type << 8; payload = len; @@ -105,10 +105,10 @@ static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) return 0; } -u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { u16 payload; - u32 ret; + int ret; u8 rds_text[] = "Zoom2\n"; fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, @@ -148,10 +148,10 @@ u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) return 0; } -u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) +int fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -176,10 +176,10 @@ u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) return 0; } -u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) +int fm_tx_set_af(struct fmdev *fmdev, u32 af) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -196,10 +196,10 @@ u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) return 0; } -u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) +int fm_tx_set_region(struct fmdev *fmdev, u8 region) { u16 payload; - u32 ret; + int ret; if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { fmerr("Invalid band\n"); @@ -216,10 +216,10 @@ u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) return 0; } -u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { u16 payload; - u32 ret; + int ret; fmdbg("tx: mute mode %d\n", mute_mode_toset); @@ -233,11 +233,11 @@ u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } /* Set TX Audio I/O */ -static u32 set_audio_io(struct fmdev *fmdev) +static int set_audio_io(struct fmdev *fmdev) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload; - u32 ret; + int ret; /* Set Audio I/O Enable */ payload = tx->audio_io; @@ -251,12 +251,12 @@ static u32 set_audio_io(struct fmdev *fmdev) } /* Start TX Transmission */ -static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) +static int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) { struct fmtx_data *tx = &fmdev->tx_data; unsigned long timeleft; u16 payload; - u32 ret; + int ret; /* Enable POWER_ENB interrupts */ payload = FM_POW_ENB_EVENT; @@ -289,11 +289,11 @@ static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) } /* Set TX power level */ -u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) +int fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) { u16 payload; struct fmtx_data *tx = &fmdev->tx_data; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -328,11 +328,11 @@ u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) * Convert V4L2 specified filter values to chip specific filter values. */ -u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) +int fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -360,10 +360,11 @@ u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) } /* Get the TX tuning capacitor value.*/ -u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) +int fm_tx_get_tune_cap_val(struct fmdev *fmdev) { u16 curr_val; - u32 ret, resp_len; + u32 resp_len; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -379,11 +380,11 @@ u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) } /* Set TX Frequency */ -u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) +int fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload, chanl_index; - u32 ret; + int ret; if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { enable_xmit(fmdev, 0); diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h index e393a2bdd49..11ae2e4c2d0 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.h +++ b/drivers/media/radio/wl128x/fmdrv_tx.h @@ -22,16 +22,16 @@ #ifndef _FMDRV_TX_H #define _FMDRV_TX_H -u32 fm_tx_set_freq(struct fmdev *, u32); -u32 fm_tx_set_pwr_lvl(struct fmdev *, u8); -u32 fm_tx_set_region(struct fmdev *, u8); -u32 fm_tx_set_mute_mode(struct fmdev *, u8); -u32 fm_tx_set_stereo_mono(struct fmdev *, u16); -u32 fm_tx_set_rds_mode(struct fmdev *, u8); -u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8); -u32 fm_tx_set_af(struct fmdev *, u32); -u32 fm_tx_set_preemph_filter(struct fmdev *, u32); -u32 fm_tx_get_tune_cap_val(struct fmdev *); +int fm_tx_set_freq(struct fmdev *, u32); +int fm_tx_set_pwr_lvl(struct fmdev *, u8); +int fm_tx_set_region(struct fmdev *, u8); +int fm_tx_set_mute_mode(struct fmdev *, u8); +int fm_tx_set_stereo_mono(struct fmdev *, u16); +int fm_tx_set_rds_mode(struct fmdev *, u8); +int fm_tx_set_radio_text(struct fmdev *, u8 *, u8); +int fm_tx_set_af(struct fmdev *, u32); +int fm_tx_set_preemph_filter(struct fmdev *, u32); +int fm_tx_get_tune_cap_val(struct fmdev *); #endif diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 87010724f91..b55012c1184 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -28,6 +28,8 @@ * */ +#include <linux/export.h> + #include "fmdrv.h" #include "fmdrv_v4l2.h" #include "fmdrv_common.h" @@ -54,23 +56,29 @@ static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf, return -EIO; } - /* Turn on RDS mode , if it is disabled */ + if (mutex_lock_interruptible(&fmdev->mutex)) + return -ERESTARTSYS; + + /* Turn on RDS mode if it is disabled */ ret = fm_rx_get_rds_mode(fmdev, &rds_mode); if (ret < 0) { fmerr("Unable to read current rds mode\n"); - return ret; + goto read_unlock; } if (rds_mode == FM_RDS_DISABLE) { ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE); if (ret < 0) { fmerr("Failed to enable rds mode\n"); - return ret; + goto read_unlock; } } /* Copy RDS data from internal buffer to user buffer */ - return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count); + ret = fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count); +read_unlock: + mutex_unlock(&fmdev->mutex); + return ret; } /* Write TX RDS data */ @@ -82,14 +90,20 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, struct fmdev *fmdev; ret = copy_from_user(&rds, buf, sizeof(rds)); + rds.text[sizeof(rds.text) - 1] = '\0'; fmdbg("(%d)type: %d, text %s, af %d\n", ret, rds.text_type, rds.text, rds.af_freq); + if (ret) + return -EFAULT; fmdev = video_drvdata(file); + if (mutex_lock_interruptible(&fmdev->mutex)) + return -ERESTARTSYS; fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); fm_tx_set_af(fmdev, rds.af_freq); + mutex_unlock(&fmdev->mutex); - return 0; + return sizeof(rds); } static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) @@ -98,7 +112,9 @@ static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) struct fmdev *fmdev; fmdev = video_drvdata(file); + mutex_lock(&fmdev->mutex); ret = fmc_is_rds_data_available(fmdev, file, pts); + mutex_unlock(&fmdev->mutex); if (ret < 0) return POLLIN | POLLRDNORM; @@ -122,10 +138,12 @@ static int fm_v4l2_fops_open(struct file *file) fmdev = video_drvdata(file); + if (mutex_lock_interruptible(&fmdev->mutex)) + return -ERESTARTSYS; ret = fmc_prepare(fmdev); if (ret < 0) { fmerr("Unable to prepare FM CORE\n"); - return ret; + goto open_unlock; } fmdbg("Load FM RX firmware..\n"); @@ -133,10 +151,12 @@ static int fm_v4l2_fops_open(struct file *file) ret = fmc_set_mode(fmdev, FM_MODE_RX); if (ret < 0) { fmerr("Unable to load FM RX firmware\n"); - return ret; + goto open_unlock; } radio_disconnected = 1; +open_unlock: + mutex_unlock(&fmdev->mutex); return ret; } @@ -151,19 +171,22 @@ static int fm_v4l2_fops_release(struct file *file) return 0; } + mutex_lock(&fmdev->mutex); ret = fmc_set_mode(fmdev, FM_MODE_OFF); if (ret < 0) { fmerr("Unable to turn off the chip\n"); - return ret; + goto release_unlock; } ret = fmc_release(fmdev); if (ret < 0) { fmerr("FM CORE release failed\n"); - return ret; + goto release_unlock; } radio_disconnected = 0; +release_unlock: + mutex_unlock(&fmdev->mutex); return ret; } @@ -175,7 +198,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME, sizeof(capability->card)); sprintf(capability->bus_info, "UART"); - capability->version = FM_DRV_RADIO_VERSION; capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | @@ -191,7 +213,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev); + ctrl->val = fm_tx_get_tune_cap_val(fmdev); break; default: fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); @@ -236,7 +258,7 @@ static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv, } static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio) + const struct v4l2_audio *audio) { if (audio->index != 0) return -EINVAL; @@ -281,7 +303,9 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0); tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_LOW; + V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | + V4L2_TUNER_CAP_HWSEEK_WRAP; tuner->audmode = (stereo_mono_mode ? V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); @@ -307,7 +331,7 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, * Should we set other tuner attributes, too? */ static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct fmdev *fmdev = video_drvdata(file); u16 aud_mode; @@ -364,7 +388,7 @@ static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, /* Set tuner or modulator radio frequency */ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct fmdev *fmdev = video_drvdata(file); @@ -372,18 +396,19 @@ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency * in units of 62.5 Hz. */ - freq->frequency = (u32)(freq->frequency / 16); - - return fmc_set_freq(fmdev, freq->frequency); + return fmc_set_freq(fmdev, freq->frequency / 16); } /* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, - struct v4l2_hw_freq_seek *seek) + const struct v4l2_hw_freq_seek *seek) { struct fmdev *fmdev = video_drvdata(file); int ret; + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (fmdev->curr_fmmode != FM_MODE_RX) { ret = fmc_set_mode(fmdev, FM_MODE_RX); if (ret != 0) { @@ -403,7 +428,7 @@ static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv, struct v4l2_modulator *mod) { - struct fmdev *fmdev = video_drvdata(file);; + struct fmdev *fmdev = video_drvdata(file); if (mod->index != 0) return -EINVAL; @@ -424,7 +449,7 @@ static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv, /* Set modulator attributes. If mode is not TX, set to TX. */ static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv, - struct v4l2_modulator *mod) + const struct v4l2_modulator *mod) { struct fmdev *fmdev = video_drvdata(file); u8 rds_mode; @@ -491,6 +516,16 @@ static struct video_device fm_viddev_template = { .ioctl_ops = &fm_drv_ioctl_ops, .name = FM_DRV_NAME, .release = video_device_release, + /* + * To ensure both the tuner and modulator ioctls are accessible we + * set the vfl_dir to M2M to indicate this. + * + * It is not really a mem2mem device of course, but it can both receive + * and transmit using the same radio device. It's the only radio driver + * that does this and it should really be split in two radio devices, + * but that would affect applications using this driver. + */ + .vfl_dir = VFL_DIR_M2M, }; int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) @@ -498,6 +533,11 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) struct v4l2_ctrl *ctrl; int ret; + strlcpy(fmdev->v4l2_dev.name, FM_DRV_NAME, sizeof(fmdev->v4l2_dev.name)); + ret = v4l2_device_register(NULL, &fmdev->v4l2_dev); + if (ret < 0) + return ret; + /* Init mutex for core locking */ mutex_init(&fmdev->mutex); @@ -514,6 +554,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) video_set_drvdata(gradio_dev, fmdev); gradio_dev->lock = &fmdev->mutex; + gradio_dev->v4l2_dev = &fmdev->v4l2_dev; /* Register with V4L2 subsystem as RADIO device */ if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) { @@ -558,7 +599,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) 255, 1, 255); if (ctrl) - ctrl->is_volatile = 1; + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; return 0; } @@ -576,5 +617,7 @@ void *fm_v4l2_deinit_video_device(void) /* Unregister RADIO device from V4L2 subsystem */ video_unregister_device(gradio_dev); + v4l2_device_unregister(&fmdev->v4l2_dev); + return fmdev; } |
