0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include "smscoreapi.h"
0031
0032 #include <linux/moduleparam.h>
0033 #include <linux/slab.h>
0034 #include <linux/firmware.h>
0035 #include <linux/delay.h>
0036 #include <linux/mmc/card.h>
0037 #include <linux/mmc/sdio_func.h>
0038 #include <linux/mmc/sdio_ids.h>
0039 #include <linux/module.h>
0040
0041 #include "sms-cards.h"
0042 #include "smsendian.h"
0043
0044
0045
0046 #define SMSSDIO_DATA 0x00
0047 #define SMSSDIO_INT 0x04
0048 #define SMSSDIO_BLOCK_SIZE 128
0049
0050 static const struct sdio_device_id smssdio_ids[] = {
0051 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
0052 .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
0053 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
0054 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
0055 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
0056 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
0057 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
0058 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
0059 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
0060 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
0061 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_MING),
0062 .driver_data = SMS1XXX_BOARD_SIANO_MING},
0063 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_PELE),
0064 .driver_data = SMS1XXX_BOARD_SIANO_PELE},
0065 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_RIO),
0066 .driver_data = SMS1XXX_BOARD_SIANO_RIO},
0067 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_DENVER_2160),
0068 .driver_data = SMS1XXX_BOARD_SIANO_DENVER_2160},
0069 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_DENVER_1530),
0070 .driver_data = SMS1XXX_BOARD_SIANO_DENVER_1530},
0071 { },
0072 };
0073
0074 MODULE_DEVICE_TABLE(sdio, smssdio_ids);
0075
0076 struct smssdio_device {
0077 struct sdio_func *func;
0078
0079 struct smscore_device_t *coredev;
0080
0081 struct smscore_buffer_t *split_cb;
0082 };
0083
0084
0085
0086
0087
0088 static int smssdio_sendrequest(void *context, void *buffer, size_t size)
0089 {
0090 int ret = 0;
0091 struct smssdio_device *smsdev;
0092
0093 smsdev = context;
0094
0095 sdio_claim_host(smsdev->func);
0096
0097 smsendian_handle_tx_message((struct sms_msg_data *) buffer);
0098 while (size >= smsdev->func->cur_blksize) {
0099 ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
0100 buffer, smsdev->func->cur_blksize);
0101 if (ret)
0102 goto out;
0103
0104 buffer += smsdev->func->cur_blksize;
0105 size -= smsdev->func->cur_blksize;
0106 }
0107
0108 if (size) {
0109 ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
0110 buffer, size);
0111 }
0112
0113 out:
0114 sdio_release_host(smsdev->func);
0115
0116 return ret;
0117 }
0118
0119
0120
0121
0122
0123 static void smssdio_interrupt(struct sdio_func *func)
0124 {
0125 int ret;
0126
0127 struct smssdio_device *smsdev;
0128 struct smscore_buffer_t *cb;
0129 struct sms_msg_hdr *hdr;
0130 size_t size;
0131
0132 smsdev = sdio_get_drvdata(func);
0133
0134
0135
0136
0137
0138 (void)sdio_readb(func, SMSSDIO_INT, &ret);
0139 if (ret) {
0140 pr_err("Unable to read interrupt register!\n");
0141 return;
0142 }
0143
0144 if (smsdev->split_cb == NULL) {
0145 cb = smscore_getbuffer(smsdev->coredev);
0146 if (!cb) {
0147 pr_err("Unable to allocate data buffer!\n");
0148 return;
0149 }
0150
0151 ret = sdio_memcpy_fromio(smsdev->func,
0152 cb->p,
0153 SMSSDIO_DATA,
0154 SMSSDIO_BLOCK_SIZE);
0155 if (ret) {
0156 pr_err("Error %d reading initial block!\n", ret);
0157 return;
0158 }
0159
0160 hdr = cb->p;
0161
0162 if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) {
0163 smsdev->split_cb = cb;
0164 return;
0165 }
0166
0167 if (hdr->msg_length > smsdev->func->cur_blksize)
0168 size = hdr->msg_length - smsdev->func->cur_blksize;
0169 else
0170 size = 0;
0171 } else {
0172 cb = smsdev->split_cb;
0173 hdr = cb->p;
0174
0175 size = hdr->msg_length - sizeof(struct sms_msg_hdr);
0176
0177 smsdev->split_cb = NULL;
0178 }
0179
0180 if (size) {
0181 void *buffer;
0182
0183 buffer = cb->p + (hdr->msg_length - size);
0184 size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
0185
0186 BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
0187
0188
0189
0190
0191 ret = sdio_memcpy_fromio(smsdev->func,
0192 buffer,
0193 SMSSDIO_DATA,
0194 size);
0195 if (ret && ret != -EINVAL) {
0196 smscore_putbuffer(smsdev->coredev, cb);
0197 pr_err("Error %d reading data from card!\n", ret);
0198 return;
0199 }
0200
0201
0202
0203
0204
0205
0206
0207
0208 if (ret == -EINVAL) {
0209 while (size) {
0210 ret = sdio_memcpy_fromio(smsdev->func,
0211 buffer, SMSSDIO_DATA,
0212 smsdev->func->cur_blksize);
0213 if (ret) {
0214 smscore_putbuffer(smsdev->coredev, cb);
0215 pr_err("Error %d reading data from card!\n",
0216 ret);
0217 return;
0218 }
0219
0220 buffer += smsdev->func->cur_blksize;
0221 if (size > smsdev->func->cur_blksize)
0222 size -= smsdev->func->cur_blksize;
0223 else
0224 size = 0;
0225 }
0226 }
0227 }
0228
0229 cb->size = hdr->msg_length;
0230 cb->offset = 0;
0231
0232 smsendian_handle_rx_message((struct sms_msg_data *) cb->p);
0233 smscore_onresponse(smsdev->coredev, cb);
0234 }
0235
0236 static int smssdio_probe(struct sdio_func *func,
0237 const struct sdio_device_id *id)
0238 {
0239 int ret;
0240
0241 int board_id;
0242 struct smssdio_device *smsdev;
0243 struct smsdevice_params_t params;
0244
0245 board_id = id->driver_data;
0246
0247 smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
0248 if (!smsdev)
0249 return -ENOMEM;
0250
0251 smsdev->func = func;
0252
0253 memset(¶ms, 0, sizeof(struct smsdevice_params_t));
0254
0255 params.device = &func->dev;
0256 params.buffer_size = 0x5000;
0257 params.num_buffers = 22;
0258 params.context = smsdev;
0259
0260 snprintf(params.devpath, sizeof(params.devpath),
0261 "sdio\\%s", sdio_func_id(func));
0262
0263 params.sendrequest_handler = smssdio_sendrequest;
0264
0265 params.device_type = sms_get_board(board_id)->type;
0266
0267 if (params.device_type != SMS_STELLAR)
0268 params.flags |= SMS_DEVICE_FAMILY2;
0269 else {
0270
0271
0272
0273 ret = -ENODEV;
0274 goto free;
0275 }
0276
0277 ret = smscore_register_device(¶ms, &smsdev->coredev, GFP_DMA, NULL);
0278 if (ret < 0)
0279 goto free;
0280
0281 smscore_set_board_id(smsdev->coredev, board_id);
0282
0283 sdio_claim_host(func);
0284
0285 ret = sdio_enable_func(func);
0286 if (ret)
0287 goto release;
0288
0289 ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE);
0290 if (ret)
0291 goto disable;
0292
0293 ret = sdio_claim_irq(func, smssdio_interrupt);
0294 if (ret)
0295 goto disable;
0296
0297 sdio_set_drvdata(func, smsdev);
0298
0299 sdio_release_host(func);
0300
0301 ret = smscore_start_device(smsdev->coredev);
0302 if (ret < 0)
0303 goto reclaim;
0304
0305 return 0;
0306
0307 reclaim:
0308 sdio_claim_host(func);
0309 sdio_release_irq(func);
0310 disable:
0311 sdio_disable_func(func);
0312 release:
0313 sdio_release_host(func);
0314 smscore_unregister_device(smsdev->coredev);
0315 free:
0316 kfree(smsdev);
0317
0318 return ret;
0319 }
0320
0321 static void smssdio_remove(struct sdio_func *func)
0322 {
0323 struct smssdio_device *smsdev;
0324
0325 smsdev = sdio_get_drvdata(func);
0326
0327
0328 if (smsdev->split_cb)
0329 smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
0330
0331 smscore_unregister_device(smsdev->coredev);
0332
0333 sdio_claim_host(func);
0334 sdio_release_irq(func);
0335 sdio_disable_func(func);
0336 sdio_release_host(func);
0337
0338 kfree(smsdev);
0339 }
0340
0341 static struct sdio_driver smssdio_driver = {
0342 .name = "smssdio",
0343 .id_table = smssdio_ids,
0344 .probe = smssdio_probe,
0345 .remove = smssdio_remove,
0346 };
0347
0348
0349
0350
0351
0352 static int __init smssdio_module_init(void)
0353 {
0354 int ret = 0;
0355
0356 printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
0357 printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
0358
0359 ret = sdio_register_driver(&smssdio_driver);
0360
0361 return ret;
0362 }
0363
0364 static void __exit smssdio_module_exit(void)
0365 {
0366 sdio_unregister_driver(&smssdio_driver);
0367 }
0368
0369 module_init(smssdio_module_init);
0370 module_exit(smssdio_module_exit);
0371
0372 MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
0373 MODULE_AUTHOR("Pierre Ossman");
0374 MODULE_LICENSE("GPL");