diff options
-rw-r--r-- | Documentation/video4linux/README.tlg2300 | 198 | ||||
-rw-r--r-- | drivers/media/video/tlg2300/pd-common.h | 4 | ||||
-rw-r--r-- | drivers/media/video/tlg2300/pd-main.c | 36 | ||||
-rw-r--r-- | drivers/media/video/tlg2300/pd-radio.c | 107 | ||||
-rw-r--r-- | drivers/media/video/tlg2300/pd-video.c | 59 |
5 files changed, 135 insertions, 269 deletions
diff --git a/Documentation/video4linux/README.tlg2300 b/Documentation/video4linux/README.tlg2300 index 82417db..416ccb9 100644 --- a/Documentation/video4linux/README.tlg2300 +++ b/Documentation/video4linux/README.tlg2300 @@ -37,195 +37,11 @@ TESTED APPLICATIONS: --------------------------------------------------------------------------- KNOWN PROBLEMS: +about preemphasis: + You can set the preemphasis for radio by the following command: + #v4l2-ctl -d /dev/radio0 --set-ctrl=pre_emphasis_settings=1 + + "pre_emphasis_settings=1" means that you select the 50us. If you want + to select the 75us, please use "pre_emphasis_settings=2" + -country code - - The firmware of the chip needs the country code to determine - the stardards of video and audio when it runs for analog TV or radio. - The DVB-T does not need the country code. - - So you must set the country-code correctly. The V4L2 does not have - the interface,the driver has to provide a parameter `country_code'. - - You could set the coutry code in two ways, take USA as example - (The USA's country code is 1): - - [1] add the following line in /etc/modprobe.conf before you insert the - card into USB hub's port : - poseidon country_code=1 - - [2] You can also modify the parameter at runtime (before you run the - application such as VLC) - #echo 1 > /sys/module/poseidon/parameter/country_code - - The known country codes show below: - country code : country - 93 "Afghanistan" - 355 "Albania" - 213 "Algeria" - 684 "American Samoa" - 376 "Andorra" - 244 "Angola" - 54 "Argentina" - 374 "Armenia" - 61 "Australia" - 43 "Austria" - 994 "Azerbaijan" - 973 "Bahrain" - 880 "Bangladesh" - 375 "Belarus" - 32 "Belgium" - 501 "Belize" - 229 "Benin" - 591 "Bolivia" - 387 "Bosnia and Herzegovina" - 267 "Botswana" - 55 "Brazil" - 673 "Brunei Darussalam" - 359 "Bulgalia" - 226 "Burkina Faso" - 257 "Burundi" - 237 "Cameroon" - 1 "Canada" - 236 "Central African Republic" - 235 "Chad" - 56 "Chile" - 86 "China" - 57 "Colombia" - 242 "Congo" - 243 "Congo, Dem. Rep. of " - 506 "Costa Rica" - 385 "Croatia" - 53 "Cuba or Guantanamo Bay" - 357 "Cyprus" - 420 "Czech Republic" - 45 "Denmark" - 246 "Diego Garcia" - 253 "Djibouti" - 593 "Ecuador" - 20 "Egypt" - 503 "El Salvador" - 240 "Equatorial Guinea" - 372 "Estonia" - 251 "Ethiopia" - 358 "Finland" - 33 "France" - 594 "French Guiana" - 689 "French Polynesia" - 241 "Gabonese Republic" - 220 "Gambia" - 995 "Georgia" - 49 "Germany" - 233 "Ghana" - 350 "Gibraltar" - 30 "Greece" - 299 "Greenland" - 671 "Guam" - 502 "Guatemala" - 592 "Guyana" - 509 "Haiti" - 504 "Honduras" - 852 "Hong Kong SAR, China" - 36 "Hungary" - 354 "Iceland" - 91 "India" - 98 "Iran" - 964 "Iraq" - 353 "Ireland" - 972 "Israel" - 39 "Italy or Vatican City" - 225 "Ivory Coast" - 81 "Japan" - 962 "Jordan" - 7 "Kazakhstan or Kyrgyzstan" - 254 "Kenya" - 686 "Kiribati" - 965 "Kuwait" - 856 "Laos" - 371 "Latvia" - 961 "Lebanon" - 266 "Lesotho" - 231 "Liberia" - 218 "Libya" - 41 "Liechtenstein or Switzerland" - 370 "Lithuania" - 352 "Luxembourg" - 853 "Macau SAR, China" - 261 "Madagascar" - 60 "Malaysia" - 960 "Maldives" - 223 "Mali Republic" - 356 "Malta" - 692 "Marshall Islands" - 596 "Martinique" - 222 "Mauritania" - 230 "Mauritus" - 52 "Mexico" - 691 "Micronesia" - 373 "Moldova" - 377 "Monaco" - 976 "Mongolia" - 212 "Morocco" - 258 "Mozambique" - 95 "Myanmar" - 264 "Namibia" - 674 "Nauru" - 31 "Netherlands" - 687 "New Caledonia" - 64 "New Zealand" - 505 "Nicaragua" - 227 "Niger" - 234 "Nigeria" - 850 "North Korea" - 47 "Norway" - 968 "Oman" - 92 "Pakistan" - 680 "Palau" - 507 "Panama" - 675 "Papua New Guinea" - 595 "Paraguay" - 51 "Peru" - 63 "Philippines" - 48 "Poland" - 351 "Portugal" - 974 "Qatar" - 262 "Reunion Island" - 40 "Romania" - 7 "Russia" - 378 "San Marino" - 239 "Sao Tome and Principe" - 966 "Saudi Arabia" - 221 "Senegal" - 248 "Seychelles Republic" - 232 "Sierra Leone" - 65 "Singapore" - 421 "Slovak Republic" - 386 "Slovenia" - 27 "South Africa" - 82 "South Korea " - 34 "Spain" - 94 "Sri Lanka" - 508 "St. Pierre and Miquelon" - 249 "Sudan" - 597 "Suriname" - 268 "Swaziland" - 46 "Sweden" - 963 "Syria" - 886 "Taiwan Region" - 255 "Tanzania" - 66 "Thailand" - 228 "Togolese Republic" - 216 "Tunisia" - 90 "Turkey" - 993 "Turkmenistan" - 256 "Uganda" - 380 "Ukraine" - 971 "United Arab Emirates" - 44 "United Kingdom" - 1 "United States of America" - 598 "Uruguay" - 58 "Venezuela" - 84 "Vietnam" - 967 "Yemen" - 260 "Zambia" - 255 "Zanzibar" - 263 "Zimbabwe" diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h index 619fd00..ae9cb6c 100644 --- a/drivers/media/video/tlg2300/pd-common.h +++ b/drivers/media/video/tlg2300/pd-common.h @@ -118,6 +118,7 @@ struct radio_data { __u32 fm_freq; int users; unsigned int is_radio_streaming; + int pre_emphasis; struct video_device *fm_dev; }; @@ -185,7 +186,6 @@ struct poseidon { struct pd_dvb_adapter dvb_data; /* DVB */ u32 state; - int country_code; struct file *file_for_stream; /* the active stream*/ #ifdef CONFIG_PM @@ -240,7 +240,6 @@ struct video_device *vdev_init(struct poseidon *, struct video_device *); int send_set_req(struct poseidon*, u8, s32, s32*); int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32); s32 set_tuner_mode(struct poseidon*, unsigned char); -enum tlg__analog_audio_standard get_audio_std(s32, s32); /* bulk urb alloc/free */ int alloc_bulk_urbs_generic(struct urb **urb_array, int num, @@ -252,7 +251,6 @@ void free_all_urb_generic(struct urb **urb_array, int num); /* misc */ void poseidon_delete(struct kref *kref); void destroy_video_device(struct video_device **v_dev); -extern int country_code; extern int debug_mode; void set_debug_mode(struct video_device *vfd, int debug_mode); diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c index 6df9380..fdcc500 100644 --- a/drivers/media/video/tlg2300/pd-main.c +++ b/drivers/media/video/tlg2300/pd-main.c @@ -189,41 +189,6 @@ int set_tuner_mode(struct poseidon *pd, unsigned char mode) return 0; } -enum tlg__analog_audio_standard get_audio_std(s32 mode, s32 country_code) -{ - s32 nicam[] = {27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64, - 65, 86, 351, 352, 353, 354, 358, 372, 852, 972}; - s32 btsc[] = {1, 52, 54, 55, 886}; - s32 eiaj[] = {81}; - s32 i; - - if (mode == TLG_MODE_FM_RADIO) { - if (country_code == 1) - return TLG_TUNE_ASTD_FM_US; - else - return TLG_TUNE_ASTD_FM_EUR; - } else if (mode == TLG_MODE_ANALOG_TV_UNCOMP) { - for (i = 0; i < sizeof(nicam) / sizeof(s32); i++) { - if (country_code == nicam[i]) - return TLG_TUNE_ASTD_NICAM; - } - - for (i = 0; i < sizeof(btsc) / sizeof(s32); i++) { - if (country_code == btsc[i]) - return TLG_TUNE_ASTD_BTSC; - } - - for (i = 0; i < sizeof(eiaj) / sizeof(s32); i++) { - if (country_code == eiaj[i]) - return TLG_TUNE_ASTD_EIAJ; - } - - return TLG_TUNE_ASTD_A2; - } else { - return TLG_TUNE_ASTD_NONE; - } -} - void poseidon_delete(struct kref *kref) { struct poseidon *pd = container_of(kref, struct poseidon, kref); @@ -462,7 +427,6 @@ static int poseidon_probe(struct usb_interface *interface, struct device *dev = &interface->dev; logpm(pd); - pd->country_code = 86; mutex_init(&pd->lock); /* register v4l2 device */ diff --git a/drivers/media/video/tlg2300/pd-radio.c b/drivers/media/video/tlg2300/pd-radio.c index bdbb0c1..755766b1 100644 --- a/drivers/media/video/tlg2300/pd-radio.c +++ b/drivers/media/video/tlg2300/pd-radio.c @@ -22,9 +22,16 @@ static int poseidon_fm_open(struct file *filp); #define TUNER_FREQ_MIN_FM 76000000 #define TUNER_FREQ_MAX_FM 108000000 +#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1) +static int preemphasis[MAX_PREEMPHASIS] = { + TLG_TUNE_ASTD_NONE, /* V4L2_PREEMPHASIS_DISABLED */ + TLG_TUNE_ASTD_FM_EUR, /* V4L2_PREEMPHASIS_50_uS */ + TLG_TUNE_ASTD_FM_US, /* V4L2_PREEMPHASIS_75_uS */ +}; + static int poseidon_check_mode_radio(struct poseidon *p) { - int ret, radiomode; + int ret; u32 status; set_current_state(TASK_INTERRUPTIBLE); @@ -38,8 +45,8 @@ static int poseidon_check_mode_radio(struct poseidon *p) goto out; ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status); - radiomode = get_audio_std(TLG_MODE_FM_RADIO, p->country_code); - ret = send_set_req(p, TUNER_AUD_ANA_STD, radiomode, &status); + ret = send_set_req(p, TUNER_AUD_ANA_STD, + p->radio_data.pre_emphasis, &status); ret |= send_set_req(p, TUNER_AUD_MODE, TLG_TUNE_TVAUDIO_MODE_STEREO, &status); ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL, @@ -91,7 +98,9 @@ static int poseidon_fm_open(struct file *filp) usb_autopm_get_interface(p->interface); if (0 == p->state) { - p->country_code = country_code; + /* default pre-emphasis */ + if (p->radio_data.pre_emphasis == 0) + p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR; set_debug_mode(vfd, debug_mode); ret = poseidon_check_mode_radio(p); @@ -205,13 +214,12 @@ int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp) static int set_frequency(struct poseidon *p, __u32 frequency) { __u32 freq ; - int ret, status, radiomode; + int ret, status; mutex_lock(&p->lock); - radiomode = get_audio_std(TLG_MODE_FM_RADIO, p->country_code); - /*NTSC 8,PAL 2 */ - ret = send_set_req(p, TUNER_AUD_ANA_STD, radiomode, &status); + ret = send_set_req(p, TUNER_AUD_ANA_STD, + p->radio_data.pre_emphasis, &status); freq = (frequency * 125) * 500 / 1000;/* kHZ */ if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) { @@ -253,27 +261,86 @@ int fm_set_freq(struct file *file, void *priv, struct v4l2_frequency *argp) int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *arg) { - return 0; + return 0; +} + +int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh, + struct v4l2_ext_controls *ctrls) +{ + struct poseidon *p = file->private_data; + int i; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) + return -EINVAL; + + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) + continue; + + if (i < MAX_PREEMPHASIS) + ctrl->value = p->radio_data.pre_emphasis; + } + return 0; } -int tlg_fm_vidioc_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *a) +int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh, + struct v4l2_ext_controls *ctrls) { - return 0; + int i; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) + return -EINVAL; + + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) + continue; + + if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) { + struct poseidon *p = file->private_data; + int pre_emphasis = preemphasis[ctrl->value]; + u32 status; + + send_set_req(p, TUNER_AUD_ANA_STD, + pre_emphasis, &status); + p->radio_data.pre_emphasis = pre_emphasis; + } + } + return 0; } int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *arg) + struct v4l2_control *ctrl) { - return 0; + return 0; } int tlg_fm_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *arg) + struct v4l2_queryctrl *ctrl) { - arg->minimum = 0; - arg->maximum = 65535; - return 0; + if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) + return -EINVAL; + + ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL; + if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) { + /* return the next supported control */ + ctrl->id = V4L2_CID_TUNE_PREEMPHASIS; + v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED, + V4L2_PREEMPHASIS_75_uS, 1, + V4L2_PREEMPHASIS_50_uS); + ctrl->flags = V4L2_CTRL_FLAG_UPDATE; + return 0; + } + return -EINVAL; +} + +int tlg_fm_vidioc_querymenu(struct file *file, void *fh, + struct v4l2_querymenu *qmenu) +{ + return v4l2_ctrl_query_menu(qmenu, NULL, NULL); } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) @@ -311,9 +378,11 @@ static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = tlg_fm_vidioc_queryctrl, + .vidioc_querymenu = tlg_fm_vidioc_querymenu, .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl, .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl, - .vidioc_s_ext_ctrls = tlg_fm_vidioc_exts_ctrl, + .vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl, + .vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_tuner = tlg_fm_vidioc_g_tuner, .vidioc_g_frequency = fm_get_freq, diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c index 5f0300a..becfba6 100644 --- a/drivers/media/video/tlg2300/pd-video.c +++ b/drivers/media/video/tlg2300/pd-video.c @@ -15,10 +15,6 @@ static int pm_video_suspend(struct poseidon *pd); static int pm_video_resume(struct poseidon *pd); static void iso_bubble_handler(struct work_struct *w); -int country_code = 86; -module_param(country_code, int, 0644); -MODULE_PARM_DESC(country_code, "country code (e.g China is 86)"); - int usb_transfer_mode; module_param(usb_transfer_mode, int, 0644); MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous"); @@ -93,27 +89,53 @@ static struct poseidon_control controls[] = { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, "brightness", 0, 10000, 1, 100, 0, }, CUST_PARM_ID_BRIGHTNESS_CTRL - }, - - { + }, { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, "contrast", 0, 10000, 1, 100, 0, }, CUST_PARM_ID_CONTRAST_CTRL, - }, - - { + }, { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, "hue", 0, 10000, 1, 100, 0, }, CUST_PARM_ID_HUE_CTRL, - }, - - { + }, { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, "saturation", 0, 10000, 1, 100, 0, }, CUST_PARM_ID_SATURATION_CTRL, }, }; +struct video_std_to_audio_std { + v4l2_std_id video_std; + int audio_std; +}; + +static const struct video_std_to_audio_std video_to_audio_map[] = { + /* country : { 27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64, + 65, 86, 351, 352, 353, 354, 358, 372, 852, 972 } */ + { (V4L2_STD_PAL_I | V4L2_STD_PAL_B | V4L2_STD_PAL_D | + V4L2_STD_SECAM_L | V4L2_STD_SECAM_D), TLG_TUNE_ASTD_NICAM }, + + /* country : { 1, 52, 54, 55, 886 } */ + {V4L2_STD_NTSC_M | V4L2_STD_PAL_N | V4L2_STD_PAL_M, TLG_TUNE_ASTD_BTSC}, + + /* country : { 81 } */ + { V4L2_STD_NTSC_M_JP, TLG_TUNE_ASTD_EIAJ }, + + /* other country : TLG_TUNE_ASTD_A2 */ +}; +static const unsigned int map_size = ARRAY_SIZE(video_to_audio_map); + +static int get_audio_std(v4l2_std_id v4l2_std) +{ + int i = 0; + + for (; i < map_size; i++) { + if (v4l2_std & video_to_audio_map[i].video_std) + return video_to_audio_map[i].audio_std; + } + return TLG_TUNE_ASTD_A2; +} + static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { @@ -1067,7 +1089,7 @@ static int pd_vidioc_s_tuner(struct poseidon *pd, int index) mutex_lock(&pd->lock); param = pd_audio_modes[index].tlg_audio_mode; ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status); - audiomode = get_audio_std(TLG_MODE_ANALOG_TV, pd->country_code); + audiomode = get_audio_std(pd->video_data.context.tvnormid); ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status); if (!ret) @@ -1255,9 +1277,7 @@ static int vidioc_streamoff(struct file *file, void *fh, return videobuf_streamoff(&front->q); } -/* - * Set the firmware' default values : need altersetting and country code - */ +/* Set the firmware's default values : need altersetting */ static int pd_video_checkmode(struct poseidon *pd) { s32 ret = 0, cmd_status, audiomode; @@ -1286,8 +1306,8 @@ static int pd_video_checkmode(struct poseidon *pd) ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status); ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */ - /* need country code to set the audio */ - audiomode = get_audio_std(TLG_MODE_ANALOG_TV, pd->country_code); + /* set the audio */ + audiomode = get_audio_std(pd->video_data.context.tvnormid); ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status); ret |= send_set_req(pd, TUNER_AUD_MODE, TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status); @@ -1392,7 +1412,6 @@ static int pd_video_open(struct file *file) goto out; pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */ - pd->country_code = country_code; init_video_context(&pd->video_data.context); ret = pd_video_checkmode(pd); |