diff options
Diffstat (limited to 'linux-2.6-v4l-dvb-update.patch')
-rw-r--r-- | linux-2.6-v4l-dvb-update.patch | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/linux-2.6-v4l-dvb-update.patch b/linux-2.6-v4l-dvb-update.patch new file mode 100644 index 0000000..814bff1 --- /dev/null +++ b/linux-2.6-v4l-dvb-update.patch @@ -0,0 +1,366 @@ +Mauro Carvalho Chehab (1): + Merge branch 'next' of ../devel into Fedora + +Uri Shkolnik (1): + V4L/DVB (11241): Siano: SDIO interface driver - remove two redundant lines + +diff --git a/linux/drivers/media/dvb/siano/smssdio.c b/linux/drivers/media/dvb/siano/smssdio.c +new file mode 100644 +index 0000000..4f8fa59 +--- /dev/null ++++ b/linux/drivers/media/dvb/siano/smssdio.c +@@ -0,0 +1,354 @@ ++/* ++ * smssdio.c - Siano 1xxx SDIO interface driver ++ * ++ * Copyright 2008 Pierre Ossman ++ * ++ * Based on code by Siano Mobile Silicon, Inc., ++ * Copyright (C) 2006-2008, Uri Shkolnik ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ * ++ * ++ * This hardware is a bit odd in that all transfers should be done ++ * to/from the SMSSDIO_DATA register, yet the "increase address" bit ++ * always needs to be set. ++ * ++ * Also, buffers from the card are always aligned to 128 byte ++ * boundaries. ++ */ ++ ++/* ++ * General cleanup notes: ++ * ++ * - only typedefs should be name *_t ++ * ++ * - use ERR_PTR and friends for smscore_register_device() ++ * ++ * - smscore_getbuffer should zero fields ++ * ++ * Fix stop command ++ */ ++ ++#include <linux/moduleparam.h> ++#include <linux/firmware.h> ++#include <linux/delay.h> ++#include <linux/mmc/card.h> ++#include <linux/mmc/sdio_func.h> ++#include <linux/mmc/sdio_ids.h> ++ ++#include "smscoreapi.h" ++#include "sms-cards.h" ++ ++/* Registers */ ++ ++#define SMSSDIO_DATA 0x00 ++#define SMSSDIO_INT 0x04 ++ ++static const struct sdio_device_id smssdio_ids[] = { ++ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), ++ .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, ++ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), ++ .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A}, ++ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0), ++ .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B}, ++ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0), ++ .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, ++ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), ++ .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, ++ { /* end: all zeroes */ }, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, smssdio_ids); ++ ++struct smssdio_device { ++ struct sdio_func *func; ++ ++ struct smscore_device_t *coredev; ++ ++ struct smscore_buffer_t *split_cb; ++}; ++ ++/*******************************************************************/ ++/* Siano core callbacks */ ++/*******************************************************************/ ++ ++static int smssdio_sendrequest(void *context, void *buffer, size_t size) ++{ ++ int ret; ++ struct smssdio_device *smsdev; ++ ++ smsdev = context; ++ ++ sdio_claim_host(smsdev->func); ++ ++ while (size >= smsdev->func->cur_blksize) { ++ ret = sdio_write_blocks(smsdev->func, SMSSDIO_DATA, buffer, 1); ++ if (ret) ++ goto out; ++ ++ buffer += smsdev->func->cur_blksize; ++ size -= smsdev->func->cur_blksize; ++ } ++ ++ if (size) { ++ ret = sdio_write_bytes(smsdev->func, SMSSDIO_DATA, ++ buffer, size); ++ } ++ ++out: ++ sdio_release_host(smsdev->func); ++ ++ return ret; ++} ++ ++/*******************************************************************/ ++/* SDIO callbacks */ ++/*******************************************************************/ ++ ++static void smssdio_interrupt(struct sdio_func *func) ++{ ++ int ret, isr; ++ ++ struct smssdio_device *smsdev; ++ struct smscore_buffer_t *cb; ++ struct SmsMsgHdr_ST *hdr; ++ size_t size; ++ ++ smsdev = sdio_get_drvdata(func); ++ ++ /* ++ * The interrupt register has no defined meaning. It is just ++ * a way of turning of the level triggered interrupt. ++ */ ++ isr = sdio_readb(func, SMSSDIO_INT, &ret); ++ if (ret) { ++ dev_err(&smsdev->func->dev, ++ "Unable to read interrupt register!\n"); ++ return; ++ } ++ ++ if (smsdev->split_cb == NULL) { ++ cb = smscore_getbuffer(smsdev->coredev); ++ if (!cb) { ++ dev_err(&smsdev->func->dev, ++ "Unable to allocate data buffer!\n"); ++ return; ++ } ++ ++ ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1); ++ if (ret) { ++ dev_err(&smsdev->func->dev, ++ "Error %d reading initial block!\n", ret); ++ return; ++ } ++ ++ hdr = cb->p; ++ ++ if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { ++ smsdev->split_cb = cb; ++ return; ++ } ++ ++ size = hdr->msgLength - smsdev->func->cur_blksize; ++ } else { ++ cb = smsdev->split_cb; ++ hdr = cb->p; ++ ++ size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); ++ ++ smsdev->split_cb = NULL; ++ } ++ ++ if (hdr->msgLength > smsdev->func->cur_blksize) { ++ void *buffer; ++ ++ size = ALIGN(size, 128); ++ buffer = cb->p + hdr->msgLength; ++ ++ BUG_ON(smsdev->func->cur_blksize != 128); ++ ++ /* ++ * First attempt to transfer all of it in one go... ++ */ ++ ret = sdio_read_blocks(smsdev->func, buffer, ++ SMSSDIO_DATA, size / 128); ++ if (ret && ret != -EINVAL) { ++ smscore_putbuffer(smsdev->coredev, cb); ++ dev_err(&smsdev->func->dev, ++ "Error %d reading data from card!\n", ret); ++ return; ++ } ++ ++ /* ++ * ..then fall back to one block at a time if that is ++ * not possible... ++ * ++ * (we have to do this manually because of the ++ * problem with the "increase address" bit) ++ */ ++ if (ret == -EINVAL) { ++ while (size) { ++ ret = sdio_read_blocks(smsdev->func, ++ buffer, SMSSDIO_DATA, 1); ++ if (ret) { ++ smscore_putbuffer(smsdev->coredev, cb); ++ dev_err(&smsdev->func->dev, ++ "Error %d reading " ++ "data from card!\n", ret); ++ return; ++ } ++ ++ buffer += smsdev->func->cur_blksize; ++ if (size > smsdev->func->cur_blksize) ++ size -= smsdev->func->cur_blksize; ++ else ++ size = 0; ++ } ++ } ++ } ++ ++ cb->size = hdr->msgLength; ++ cb->offset = 0; ++ ++ smscore_onresponse(smsdev->coredev, cb); ++} ++ ++static int smssdio_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int ret; ++ ++ int board_id; ++ struct smssdio_device *smsdev; ++ struct smsdevice_params_t params; ++ ++ board_id = id->driver_data; ++ ++ smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL); ++ if (!smsdev) ++ return -ENOMEM; ++ ++ smsdev->func = func; ++ ++ memset(¶ms, 0, sizeof(struct smsdevice_params_t)); ++ ++ params.device = &func->dev; ++ params.buffer_size = 0x5000; /* ?? */ ++ params.num_buffers = 22; /* ?? */ ++ params.context = smsdev; ++ ++ snprintf(params.devpath, sizeof(params.devpath), ++ "sdio\\%s", sdio_func_id(func)); ++ ++ params.sendrequest_handler = smssdio_sendrequest; ++ ++ params.device_type = sms_get_board(board_id)->type; ++ ++ if (params.device_type != SMS_STELLAR) ++ params.flags |= SMS_DEVICE_FAMILY2; ++ else { ++ /* ++ * FIXME: Stellar needs special handling... ++ */ ++ ret = -ENODEV; ++ goto free; ++ } ++ ++ ret = smscore_register_device(¶ms, &smsdev->coredev); ++ if (ret < 0) ++ goto free; ++ ++ smscore_set_board_id(smsdev->coredev, board_id); ++ ++ sdio_claim_host(func); ++ ++ ret = sdio_enable_func(func); ++ if (ret) ++ goto release; ++ ++ ret = sdio_set_block_size(func, 128); ++ if (ret) ++ goto disable; ++ ++ ret = sdio_claim_irq(func, smssdio_interrupt); ++ if (ret) ++ goto disable; ++ ++ sdio_set_drvdata(func, smsdev); ++ ++ sdio_release_host(func); ++ ++ ret = smscore_start_device(smsdev->coredev); ++ if (ret < 0) ++ goto reclaim; ++ ++ return 0; ++ ++reclaim: ++ sdio_claim_host(func); ++ sdio_release_irq(func); ++disable: ++ sdio_disable_func(func); ++release: ++ sdio_release_host(func); ++ smscore_unregister_device(smsdev->coredev); ++free: ++ kfree(smsdev); ++ ++ return ret; ++} ++ ++static void smssdio_remove(struct sdio_func *func) ++{ ++ struct smssdio_device *smsdev; ++ ++ smsdev = sdio_get_drvdata(func); ++ ++ /* FIXME: racy! */ ++ if (smsdev->split_cb) ++ smscore_putbuffer(smsdev->coredev, smsdev->split_cb); ++ ++ smscore_unregister_device(smsdev->coredev); ++ ++ sdio_claim_host(func); ++ sdio_release_irq(func); ++ sdio_disable_func(func); ++ sdio_release_host(func); ++ ++ kfree(smsdev); ++} ++ ++static struct sdio_driver smssdio_driver = { ++ .name = "smssdio", ++ .id_table = smssdio_ids, ++ .probe = smssdio_probe, ++ .remove = smssdio_remove, ++}; ++ ++/*******************************************************************/ ++/* Module functions */ ++/*******************************************************************/ ++ ++int smssdio_register(void) ++{ ++ int ret = 0; ++ ++ printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n"); ++ printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n"); ++ ++ ret = sdio_register_driver(&smssdio_driver); ++ ++ return ret; ++} ++ ++void smssdio_unregister(void) ++{ ++ sdio_unregister_driver(&smssdio_driver); ++} ++ ++MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver"); ++MODULE_AUTHOR("Pierre Ossman"); ++MODULE_LICENSE("GPL"); |