diff options
Diffstat (limited to 'drivers/media/radio/si470x')
| -rw-r--r-- | drivers/media/radio/si470x/radio-si470x-common.c | 98 | ||||
| -rw-r--r-- | drivers/media/radio/si470x/radio-si470x-i2c.c | 219 | ||||
| -rw-r--r-- | drivers/media/radio/si470x/radio-si470x-usb.c | 97 | ||||
| -rw-r--r-- | drivers/media/radio/si470x/radio-si470x.h | 5 |
4 files changed, 300 insertions, 119 deletions
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index f33315f2c543..4da0f150c6e2 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c | |||
| @@ -426,6 +426,104 @@ int si470x_rds_on(struct si470x_device *radio) | |||
| 426 | 426 | ||
| 427 | 427 | ||
| 428 | /************************************************************************** | 428 | /************************************************************************** |
| 429 | * File Operations Interface | ||
| 430 | **************************************************************************/ | ||
| 431 | |||
| 432 | /* | ||
| 433 | * si470x_fops_read - read RDS data | ||
| 434 | */ | ||
| 435 | static ssize_t si470x_fops_read(struct file *file, char __user *buf, | ||
| 436 | size_t count, loff_t *ppos) | ||
| 437 | { | ||
| 438 | struct si470x_device *radio = video_drvdata(file); | ||
| 439 | int retval = 0; | ||
| 440 | unsigned int block_count = 0; | ||
| 441 | |||
| 442 | /* switch on rds reception */ | ||
| 443 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
| 444 | si470x_rds_on(radio); | ||
| 445 | |||
| 446 | /* block if no new data available */ | ||
| 447 | while (radio->wr_index == radio->rd_index) { | ||
| 448 | if (file->f_flags & O_NONBLOCK) { | ||
| 449 | retval = -EWOULDBLOCK; | ||
| 450 | goto done; | ||
| 451 | } | ||
| 452 | if (wait_event_interruptible(radio->read_queue, | ||
| 453 | radio->wr_index != radio->rd_index) < 0) { | ||
| 454 | retval = -EINTR; | ||
| 455 | goto done; | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | /* calculate block count from byte count */ | ||
| 460 | count /= 3; | ||
| 461 | |||
| 462 | /* copy RDS block out of internal buffer and to user buffer */ | ||
| 463 | mutex_lock(&radio->lock); | ||
| 464 | while (block_count < count) { | ||
| 465 | if (radio->rd_index == radio->wr_index) | ||
| 466 | break; | ||
| 467 | |||
| 468 | /* always transfer rds complete blocks */ | ||
| 469 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) | ||
| 470 | /* retval = -EFAULT; */ | ||
| 471 | break; | ||
| 472 | |||
| 473 | /* increment and wrap read pointer */ | ||
| 474 | radio->rd_index += 3; | ||
| 475 | if (radio->rd_index >= radio->buf_size) | ||
| 476 | radio->rd_index = 0; | ||
| 477 | |||
| 478 | /* increment counters */ | ||
| 479 | block_count++; | ||
| 480 | buf += 3; | ||
| 481 | retval += 3; | ||
| 482 | } | ||
| 483 | mutex_unlock(&radio->lock); | ||
| 484 | |||
| 485 | done: | ||
| 486 | return retval; | ||
| 487 | } | ||
| 488 | |||
| 489 | |||
| 490 | /* | ||
| 491 | * si470x_fops_poll - poll RDS data | ||
| 492 | */ | ||
| 493 | static unsigned int si470x_fops_poll(struct file *file, | ||
| 494 | struct poll_table_struct *pts) | ||
| 495 | { | ||
| 496 | struct si470x_device *radio = video_drvdata(file); | ||
| 497 | int retval = 0; | ||
| 498 | |||
| 499 | /* switch on rds reception */ | ||
| 500 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
| 501 | si470x_rds_on(radio); | ||
| 502 | |||
| 503 | poll_wait(file, &radio->read_queue, pts); | ||
| 504 | |||
| 505 | if (radio->rd_index != radio->wr_index) | ||
| 506 | retval = POLLIN | POLLRDNORM; | ||
| 507 | |||
| 508 | return retval; | ||
| 509 | } | ||
| 510 | |||
| 511 | |||
| 512 | /* | ||
| 513 | * si470x_fops - file operations interface | ||
| 514 | */ | ||
| 515 | static const struct v4l2_file_operations si470x_fops = { | ||
| 516 | .owner = THIS_MODULE, | ||
| 517 | .read = si470x_fops_read, | ||
| 518 | .poll = si470x_fops_poll, | ||
| 519 | .ioctl = video_ioctl2, | ||
| 520 | .open = si470x_fops_open, | ||
| 521 | .release = si470x_fops_release, | ||
| 522 | }; | ||
| 523 | |||
| 524 | |||
| 525 | |||
| 526 | /************************************************************************** | ||
| 429 | * Video4Linux Interface | 527 | * Video4Linux Interface |
| 430 | **************************************************************************/ | 528 | **************************************************************************/ |
| 431 | 529 | ||
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2d53b6a9409b..5466015346a1 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c | |||
| @@ -22,22 +22,17 @@ | |||
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | /* | ||
| 26 | * ToDo: | ||
| 27 | * - RDS support | ||
| 28 | */ | ||
| 29 | |||
| 30 | |||
| 31 | /* driver definitions */ | 25 | /* driver definitions */ |
| 32 | #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; | 26 | #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; |
| 33 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0) | 27 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) |
| 34 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" | 28 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" |
| 35 | #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" | 29 | #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" |
| 36 | #define DRIVER_VERSION "1.0.0" | 30 | #define DRIVER_VERSION "1.0.1" |
| 37 | 31 | ||
| 38 | /* kernel includes */ | 32 | /* kernel includes */ |
| 39 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
| 40 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
| 35 | #include <linux/interrupt.h> | ||
| 41 | 36 | ||
| 42 | #include "radio-si470x.h" | 37 | #include "radio-si470x.h" |
| 43 | 38 | ||
| @@ -62,6 +57,20 @@ static int radio_nr = -1; | |||
| 62 | module_param(radio_nr, int, 0444); | 57 | module_param(radio_nr, int, 0444); |
| 63 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); | 58 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); |
| 64 | 59 | ||
| 60 | /* RDS buffer blocks */ | ||
| 61 | static unsigned int rds_buf = 100; | ||
| 62 | module_param(rds_buf, uint, 0444); | ||
| 63 | MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); | ||
| 64 | |||
| 65 | /* RDS maximum block errors */ | ||
| 66 | static unsigned short max_rds_errors = 1; | ||
| 67 | /* 0 means 0 errors requiring correction */ | ||
| 68 | /* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ | ||
| 69 | /* 2 means 3-5 errors requiring correction */ | ||
| 70 | /* 3 means 6+ errors or errors in checkword, correction not possible */ | ||
| 71 | module_param(max_rds_errors, ushort, 0644); | ||
| 72 | MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); | ||
| 73 | |||
| 65 | 74 | ||
| 66 | 75 | ||
| 67 | /************************************************************************** | 76 | /************************************************************************** |
| @@ -173,7 +182,7 @@ int si470x_disconnect_check(struct si470x_device *radio) | |||
| 173 | /* | 182 | /* |
| 174 | * si470x_fops_open - file open | 183 | * si470x_fops_open - file open |
| 175 | */ | 184 | */ |
| 176 | static int si470x_fops_open(struct file *file) | 185 | int si470x_fops_open(struct file *file) |
| 177 | { | 186 | { |
| 178 | struct si470x_device *radio = video_drvdata(file); | 187 | struct si470x_device *radio = video_drvdata(file); |
| 179 | int retval = 0; | 188 | int retval = 0; |
| @@ -181,12 +190,21 @@ static int si470x_fops_open(struct file *file) | |||
| 181 | mutex_lock(&radio->lock); | 190 | mutex_lock(&radio->lock); |
| 182 | radio->users++; | 191 | radio->users++; |
| 183 | 192 | ||
| 184 | if (radio->users == 1) | 193 | if (radio->users == 1) { |
| 185 | /* start radio */ | 194 | /* start radio */ |
| 186 | retval = si470x_start(radio); | 195 | retval = si470x_start(radio); |
| 196 | if (retval < 0) | ||
| 197 | goto done; | ||
| 198 | |||
| 199 | /* enable RDS interrupt */ | ||
| 200 | radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN; | ||
| 201 | radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; | ||
| 202 | radio->registers[SYSCONFIG1] |= 0x1 << 2; | ||
| 203 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
| 204 | } | ||
| 187 | 205 | ||
| 206 | done: | ||
| 188 | mutex_unlock(&radio->lock); | 207 | mutex_unlock(&radio->lock); |
| 189 | |||
| 190 | return retval; | 208 | return retval; |
| 191 | } | 209 | } |
| 192 | 210 | ||
| @@ -194,7 +212,7 @@ static int si470x_fops_open(struct file *file) | |||
| 194 | /* | 212 | /* |
| 195 | * si470x_fops_release - file release | 213 | * si470x_fops_release - file release |
| 196 | */ | 214 | */ |
| 197 | static int si470x_fops_release(struct file *file) | 215 | int si470x_fops_release(struct file *file) |
| 198 | { | 216 | { |
| 199 | struct si470x_device *radio = video_drvdata(file); | 217 | struct si470x_device *radio = video_drvdata(file); |
| 200 | int retval = 0; | 218 | int retval = 0; |
| @@ -215,17 +233,6 @@ static int si470x_fops_release(struct file *file) | |||
| 215 | } | 233 | } |
| 216 | 234 | ||
| 217 | 235 | ||
| 218 | /* | ||
| 219 | * si470x_fops - file operations interface | ||
| 220 | */ | ||
| 221 | const struct v4l2_file_operations si470x_fops = { | ||
| 222 | .owner = THIS_MODULE, | ||
| 223 | .ioctl = video_ioctl2, | ||
| 224 | .open = si470x_fops_open, | ||
| 225 | .release = si470x_fops_release, | ||
| 226 | }; | ||
| 227 | |||
| 228 | |||
| 229 | 236 | ||
| 230 | /************************************************************************** | 237 | /************************************************************************** |
| 231 | * Video4Linux Interface | 238 | * Video4Linux Interface |
| @@ -253,6 +260,105 @@ int si470x_vidioc_querycap(struct file *file, void *priv, | |||
| 253 | **************************************************************************/ | 260 | **************************************************************************/ |
| 254 | 261 | ||
| 255 | /* | 262 | /* |
| 263 | * si470x_i2c_interrupt_work - rds processing function | ||
| 264 | */ | ||
| 265 | static void si470x_i2c_interrupt_work(struct work_struct *work) | ||
| 266 | { | ||
| 267 | struct si470x_device *radio = container_of(work, | ||
| 268 | struct si470x_device, radio_work); | ||
| 269 | unsigned char regnr; | ||
| 270 | unsigned char blocknum; | ||
| 271 | unsigned short bler; /* rds block errors */ | ||
| 272 | unsigned short rds; | ||
| 273 | unsigned char tmpbuf[3]; | ||
| 274 | int retval = 0; | ||
| 275 | |||
| 276 | /* safety checks */ | ||
| 277 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
| 278 | return; | ||
| 279 | |||
| 280 | /* Update RDS registers */ | ||
| 281 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { | ||
| 282 | retval = si470x_get_register(radio, STATUSRSSI + regnr); | ||
| 283 | if (retval < 0) | ||
| 284 | return; | ||
| 285 | } | ||
| 286 | |||
| 287 | /* get rds blocks */ | ||
| 288 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) | ||
| 289 | /* No RDS group ready, better luck next time */ | ||
| 290 | return; | ||
| 291 | |||
| 292 | for (blocknum = 0; blocknum < 4; blocknum++) { | ||
| 293 | switch (blocknum) { | ||
| 294 | default: | ||
| 295 | bler = (radio->registers[STATUSRSSI] & | ||
| 296 | STATUSRSSI_BLERA) >> 9; | ||
| 297 | rds = radio->registers[RDSA]; | ||
| 298 | break; | ||
| 299 | case 1: | ||
| 300 | bler = (radio->registers[READCHAN] & | ||
| 301 | READCHAN_BLERB) >> 14; | ||
| 302 | rds = radio->registers[RDSB]; | ||
| 303 | break; | ||
| 304 | case 2: | ||
| 305 | bler = (radio->registers[READCHAN] & | ||
| 306 | READCHAN_BLERC) >> 12; | ||
| 307 | rds = radio->registers[RDSC]; | ||
| 308 | break; | ||
| 309 | case 3: | ||
| 310 | bler = (radio->registers[READCHAN] & | ||
| 311 | READCHAN_BLERD) >> 10; | ||
| 312 | rds = radio->registers[RDSD]; | ||
| 313 | break; | ||
| 314 | }; | ||
| 315 | |||
| 316 | /* Fill the V4L2 RDS buffer */ | ||
| 317 | put_unaligned_le16(rds, &tmpbuf); | ||
| 318 | tmpbuf[2] = blocknum; /* offset name */ | ||
| 319 | tmpbuf[2] |= blocknum << 3; /* received offset */ | ||
| 320 | if (bler > max_rds_errors) | ||
| 321 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ | ||
| 322 | else if (bler > 0) | ||
| 323 | tmpbuf[2] |= 0x40; /* corrected error(s) */ | ||
| 324 | |||
| 325 | /* copy RDS block to internal buffer */ | ||
| 326 | memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); | ||
| 327 | radio->wr_index += 3; | ||
| 328 | |||
| 329 | /* wrap write pointer */ | ||
| 330 | if (radio->wr_index >= radio->buf_size) | ||
| 331 | radio->wr_index = 0; | ||
| 332 | |||
| 333 | /* check for overflow */ | ||
| 334 | if (radio->wr_index == radio->rd_index) { | ||
| 335 | /* increment and wrap read pointer */ | ||
| 336 | radio->rd_index += 3; | ||
| 337 | if (radio->rd_index >= radio->buf_size) | ||
| 338 | radio->rd_index = 0; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | if (radio->wr_index != radio->rd_index) | ||
| 343 | wake_up_interruptible(&radio->read_queue); | ||
| 344 | } | ||
| 345 | |||
| 346 | |||
| 347 | /* | ||
| 348 | * si470x_i2c_interrupt - interrupt handler | ||
| 349 | */ | ||
| 350 | static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) | ||
| 351 | { | ||
| 352 | struct si470x_device *radio = dev_id; | ||
| 353 | |||
| 354 | if (!work_pending(&radio->radio_work)) | ||
| 355 | schedule_work(&radio->radio_work); | ||
| 356 | |||
| 357 | return IRQ_HANDLED; | ||
| 358 | } | ||
| 359 | |||
| 360 | |||
| 361 | /* | ||
| 256 | * si470x_i2c_probe - probe for the device | 362 | * si470x_i2c_probe - probe for the device |
| 257 | */ | 363 | */ |
| 258 | static int __devinit si470x_i2c_probe(struct i2c_client *client, | 364 | static int __devinit si470x_i2c_probe(struct i2c_client *client, |
| @@ -268,6 +374,8 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
| 268 | retval = -ENOMEM; | 374 | retval = -ENOMEM; |
| 269 | goto err_initial; | 375 | goto err_initial; |
| 270 | } | 376 | } |
| 377 | |||
| 378 | INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work); | ||
| 271 | radio->users = 0; | 379 | radio->users = 0; |
| 272 | radio->client = client; | 380 | radio->client = client; |
| 273 | mutex_init(&radio->lock); | 381 | mutex_init(&radio->lock); |
| @@ -319,6 +427,26 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
| 319 | /* set initial frequency */ | 427 | /* set initial frequency */ |
| 320 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ | 428 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ |
| 321 | 429 | ||
| 430 | /* rds buffer allocation */ | ||
| 431 | radio->buf_size = rds_buf * 3; | ||
| 432 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | ||
| 433 | if (!radio->buffer) { | ||
| 434 | retval = -EIO; | ||
| 435 | goto err_video; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* rds buffer configuration */ | ||
| 439 | radio->wr_index = 0; | ||
| 440 | radio->rd_index = 0; | ||
| 441 | init_waitqueue_head(&radio->read_queue); | ||
| 442 | |||
| 443 | retval = request_irq(client->irq, si470x_i2c_interrupt, | ||
| 444 | IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); | ||
| 445 | if (retval) { | ||
| 446 | dev_err(&client->dev, "Failed to register interrupt\n"); | ||
| 447 | goto err_rds; | ||
| 448 | } | ||
| 449 | |||
| 322 | /* register video device */ | 450 | /* register video device */ |
| 323 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, | 451 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, |
| 324 | radio_nr); | 452 | radio_nr); |
| @@ -330,6 +458,9 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
| 330 | 458 | ||
| 331 | return 0; | 459 | return 0; |
| 332 | err_all: | 460 | err_all: |
| 461 | free_irq(client->irq, radio); | ||
| 462 | err_rds: | ||
| 463 | kfree(radio->buffer); | ||
| 333 | err_video: | 464 | err_video: |
| 334 | video_device_release(radio->videodev); | 465 | video_device_release(radio->videodev); |
| 335 | err_radio: | 466 | err_radio: |
| @@ -346,6 +477,8 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) | |||
| 346 | { | 477 | { |
| 347 | struct si470x_device *radio = i2c_get_clientdata(client); | 478 | struct si470x_device *radio = i2c_get_clientdata(client); |
| 348 | 479 | ||
| 480 | free_irq(client->irq, radio); | ||
| 481 | cancel_work_sync(&radio->radio_work); | ||
| 349 | video_unregister_device(radio->videodev); | 482 | video_unregister_device(radio->videodev); |
| 350 | kfree(radio); | 483 | kfree(radio); |
| 351 | i2c_set_clientdata(client, NULL); | 484 | i2c_set_clientdata(client, NULL); |
| @@ -354,6 +487,44 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) | |||
| 354 | } | 487 | } |
| 355 | 488 | ||
| 356 | 489 | ||
| 490 | #ifdef CONFIG_PM | ||
| 491 | /* | ||
| 492 | * si470x_i2c_suspend - suspend the device | ||
| 493 | */ | ||
| 494 | static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg) | ||
| 495 | { | ||
| 496 | struct si470x_device *radio = i2c_get_clientdata(client); | ||
| 497 | |||
| 498 | /* power down */ | ||
| 499 | radio->registers[POWERCFG] |= POWERCFG_DISABLE; | ||
| 500 | if (si470x_set_register(radio, POWERCFG) < 0) | ||
| 501 | return -EIO; | ||
| 502 | |||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | |||
| 507 | /* | ||
| 508 | * si470x_i2c_resume - resume the device | ||
| 509 | */ | ||
| 510 | static int si470x_i2c_resume(struct i2c_client *client) | ||
| 511 | { | ||
| 512 | struct si470x_device *radio = i2c_get_clientdata(client); | ||
| 513 | |||
| 514 | /* power up : need 110ms */ | ||
| 515 | radio->registers[POWERCFG] |= POWERCFG_ENABLE; | ||
| 516 | if (si470x_set_register(radio, POWERCFG) < 0) | ||
| 517 | return -EIO; | ||
| 518 | msleep(110); | ||
| 519 | |||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | #else | ||
| 523 | #define si470x_i2c_suspend NULL | ||
| 524 | #define si470x_i2c_resume NULL | ||
| 525 | #endif | ||
| 526 | |||
| 527 | |||
| 357 | /* | 528 | /* |
| 358 | * si470x_i2c_driver - i2c driver interface | 529 | * si470x_i2c_driver - i2c driver interface |
| 359 | */ | 530 | */ |
| @@ -364,6 +535,8 @@ static struct i2c_driver si470x_i2c_driver = { | |||
| 364 | }, | 535 | }, |
| 365 | .probe = si470x_i2c_probe, | 536 | .probe = si470x_i2c_probe, |
| 366 | .remove = __devexit_p(si470x_i2c_remove), | 537 | .remove = __devexit_p(si470x_i2c_remove), |
| 538 | .suspend = si470x_i2c_suspend, | ||
| 539 | .resume = si470x_i2c_resume, | ||
| 367 | .id_table = si470x_i2c_id, | 540 | .id_table = si470x_i2c_id, |
| 368 | }; | 541 | }; |
| 369 | 542 | ||
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index f2d0e1ddb301..a96e1b9dd646 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c | |||
| @@ -509,89 +509,9 @@ resubmit: | |||
| 509 | **************************************************************************/ | 509 | **************************************************************************/ |
| 510 | 510 | ||
| 511 | /* | 511 | /* |
| 512 | * si470x_fops_read - read RDS data | ||
| 513 | */ | ||
| 514 | static ssize_t si470x_fops_read(struct file *file, char __user *buf, | ||
| 515 | size_t count, loff_t *ppos) | ||
| 516 | { | ||
| 517 | struct si470x_device *radio = video_drvdata(file); | ||
| 518 | int retval = 0; | ||
| 519 | unsigned int block_count = 0; | ||
| 520 | |||
| 521 | /* switch on rds reception */ | ||
| 522 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
| 523 | si470x_rds_on(radio); | ||
| 524 | |||
| 525 | /* block if no new data available */ | ||
| 526 | while (radio->wr_index == radio->rd_index) { | ||
| 527 | if (file->f_flags & O_NONBLOCK) { | ||
| 528 | retval = -EWOULDBLOCK; | ||
| 529 | goto done; | ||
| 530 | } | ||
| 531 | if (wait_event_interruptible(radio->read_queue, | ||
| 532 | radio->wr_index != radio->rd_index) < 0) { | ||
| 533 | retval = -EINTR; | ||
| 534 | goto done; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | /* calculate block count from byte count */ | ||
| 539 | count /= 3; | ||
| 540 | |||
| 541 | /* copy RDS block out of internal buffer and to user buffer */ | ||
| 542 | mutex_lock(&radio->lock); | ||
| 543 | while (block_count < count) { | ||
| 544 | if (radio->rd_index == radio->wr_index) | ||
| 545 | break; | ||
| 546 | |||
| 547 | /* always transfer rds complete blocks */ | ||
| 548 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) | ||
| 549 | /* retval = -EFAULT; */ | ||
| 550 | break; | ||
| 551 | |||
| 552 | /* increment and wrap read pointer */ | ||
| 553 | radio->rd_index += 3; | ||
| 554 | if (radio->rd_index >= radio->buf_size) | ||
| 555 | radio->rd_index = 0; | ||
| 556 | |||
| 557 | /* increment counters */ | ||
| 558 | block_count++; | ||
| 559 | buf += 3; | ||
| 560 | retval += 3; | ||
| 561 | } | ||
| 562 | mutex_unlock(&radio->lock); | ||
| 563 | |||
| 564 | done: | ||
| 565 | return retval; | ||
| 566 | } | ||
| 567 | |||
| 568 | |||
| 569 | /* | ||
| 570 | * si470x_fops_poll - poll RDS data | ||
| 571 | */ | ||
| 572 | static unsigned int si470x_fops_poll(struct file *file, | ||
| 573 | struct poll_table_struct *pts) | ||
| 574 | { | ||
| 575 | struct si470x_device *radio = video_drvdata(file); | ||
| 576 | int retval = 0; | ||
| 577 | |||
| 578 | /* switch on rds reception */ | ||
| 579 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
| 580 | si470x_rds_on(radio); | ||
| 581 | |||
| 582 | poll_wait(file, &radio->read_queue, pts); | ||
| 583 | |||
| 584 | if (radio->rd_index != radio->wr_index) | ||
| 585 | retval = POLLIN | POLLRDNORM; | ||
| 586 | |||
| 587 | return retval; | ||
| 588 | } | ||
| 589 | |||
| 590 | |||
| 591 | /* | ||
| 592 | * si470x_fops_open - file open | 512 | * si470x_fops_open - file open |
| 593 | */ | 513 | */ |
| 594 | static int si470x_fops_open(struct file *file) | 514 | int si470x_fops_open(struct file *file) |
| 595 | { | 515 | { |
| 596 | struct si470x_device *radio = video_drvdata(file); | 516 | struct si470x_device *radio = video_drvdata(file); |
| 597 | int retval; | 517 | int retval; |
| @@ -645,7 +565,7 @@ done: | |||
| 645 | /* | 565 | /* |
| 646 | * si470x_fops_release - file release | 566 | * si470x_fops_release - file release |
| 647 | */ | 567 | */ |
| 648 | static int si470x_fops_release(struct file *file) | 568 | int si470x_fops_release(struct file *file) |
| 649 | { | 569 | { |
| 650 | struct si470x_device *radio = video_drvdata(file); | 570 | struct si470x_device *radio = video_drvdata(file); |
| 651 | int retval = 0; | 571 | int retval = 0; |
| @@ -688,19 +608,6 @@ done: | |||
| 688 | } | 608 | } |
| 689 | 609 | ||
| 690 | 610 | ||
| 691 | /* | ||
| 692 | * si470x_fops - file operations interface | ||
| 693 | */ | ||
| 694 | const struct v4l2_file_operations si470x_fops = { | ||
| 695 | .owner = THIS_MODULE, | ||
| 696 | .read = si470x_fops_read, | ||
| 697 | .poll = si470x_fops_poll, | ||
| 698 | .ioctl = video_ioctl2, | ||
| 699 | .open = si470x_fops_open, | ||
| 700 | .release = si470x_fops_release, | ||
| 701 | }; | ||
| 702 | |||
| 703 | |||
| 704 | 611 | ||
| 705 | /************************************************************************** | 612 | /************************************************************************** |
| 706 | * Video4Linux Interface | 613 | * Video4Linux Interface |
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index d0af194d194c..3cd0a29cd6e7 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 32 | #include <linux/sched.h> | ||
| 32 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 33 | #include <linux/smp_lock.h> | 34 | #include <linux/smp_lock.h> |
| 34 | #include <linux/input.h> | 35 | #include <linux/input.h> |
| @@ -181,6 +182,7 @@ struct si470x_device { | |||
| 181 | 182 | ||
| 182 | #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) | 183 | #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) |
| 183 | struct i2c_client *client; | 184 | struct i2c_client *client; |
| 185 | struct work_struct radio_work; | ||
| 184 | #endif | 186 | #endif |
| 185 | }; | 187 | }; |
| 186 | 188 | ||
| @@ -212,7 +214,6 @@ struct si470x_device { | |||
| 212 | /************************************************************************** | 214 | /************************************************************************** |
| 213 | * Common Functions | 215 | * Common Functions |
| 214 | **************************************************************************/ | 216 | **************************************************************************/ |
| 215 | extern const struct v4l2_file_operations si470x_fops; | ||
| 216 | extern struct video_device si470x_viddev_template; | 217 | extern struct video_device si470x_viddev_template; |
| 217 | int si470x_get_register(struct si470x_device *radio, int regnr); | 218 | int si470x_get_register(struct si470x_device *radio, int regnr); |
| 218 | int si470x_set_register(struct si470x_device *radio, int regnr); | 219 | int si470x_set_register(struct si470x_device *radio, int regnr); |
| @@ -221,5 +222,7 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq); | |||
| 221 | int si470x_start(struct si470x_device *radio); | 222 | int si470x_start(struct si470x_device *radio); |
| 222 | int si470x_stop(struct si470x_device *radio); | 223 | int si470x_stop(struct si470x_device *radio); |
| 223 | int si470x_rds_on(struct si470x_device *radio); | 224 | int si470x_rds_on(struct si470x_device *radio); |
| 225 | int si470x_fops_open(struct file *file); | ||
| 226 | int si470x_fops_release(struct file *file); | ||
| 224 | int si470x_vidioc_querycap(struct file *file, void *priv, | 227 | int si470x_vidioc_querycap(struct file *file, void *priv, |
| 225 | struct v4l2_capability *capability); | 228 | struct v4l2_capability *capability); |
