xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/ssv6xxx/bridge/sdiobridge.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3  * Copyright (c) 2015 iComm Corporation
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <linux/irq.h>
18 #include <linux/module.h>
19 #include <linux/vmalloc.h>
20 #include <linux/platform_device.h>
21 #include <linux/mmc/sdio.h>
22 #include <linux/mmc/sdio_func.h>
23 #include <linux/mmc/sdio_ids.h>
24 #include <linux/mmc/card.h>
25 #include <linux/mmc/host.h>
26 #include <linux/gpio.h>
27 #include <linux/pm_runtime.h>
28 #include <linux/printk.h>
29 #include <linux/init.h>
30 #include <linux/module.h>
31 #include <linux/fs.h>
32 #include <linux/cdev.h>
33 #include <linux/slab.h>
34 #include <linux/uaccess.h>
35 #include <linux/version.h>
36 #include <hwif/sdio/sdio_def.h>
37 #include "sdiobridge.h"
38 #include "debug.h"
39 #define BLOCKSIZE 0x40
40 #define RXBUFLENGTH 1024*3
41 #define RXBUFSIZE 512
42 enum ssvcabrio_int
43 {
44     SSVCABRIO_INT_RX = 0x00000001,
45     SSVCABRIO_INT_TX = 0x00000002,
46     SSVCABRIO_INT_GPIO = 0x00000004,
47     SSVCABRIO_INT_SYS = 0x00000008,
48 };
49 #define CHECK_RET(_fun) \
50  do { \
51   if (0 != _fun) \
52    printk("File = %s\nLine = %d\nFunc=%s\nDate=%s\nTime=%s\n", __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); \
53  } while (0)
54 static unsigned int ssv_sdiobridge_ioctl_major = 0;
55 static unsigned int num_of_dev = 1;
56 static struct cdev ssv_sdiobridge_ioctl_cdev;
57 static struct class *fc;
58 static struct ssv_sdiobridge_glue *glue;
59 struct ssv_rxbuf
60 {
61     struct list_head list;
62     u32 rxsize;
63     u8 rxdata[RXBUFLENGTH];
64 };
65 static const struct sdio_device_id ssv_sdiobridge_devices[] =
66 {
67     {SDIO_DEVICE(MANUFACTURER_SSV_CODE, (MANUFACTURER_ID_CABRIO_BASE | 0x0))},
68     {}
69 };
70 MODULE_DEVICE_TABLE(sdio, ssv_sdiobridge_devices);
ssv_sdiobridge_ioctl_getFuncfocus(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)71 static long ssv_sdiobridge_ioctl_getFuncfocus(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
72 {
73     long retval =0;
74     if ( pcmd_data->out_data_len < 1)
75     {
76         retval = -1;
77     }
78     else
79     {
80         u8 out_data = glue->funcFocus;
81         if ( isCompat )
82         {
83             CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),&out_data,sizeof(out_data)));
84         }
85         else
86         {
87             CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data, &out_data, sizeof(out_data)));
88         }
89     }
90     return retval;
91 }
ssv_sdiobridge_ioctl_setFuncfocus(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)92 static long ssv_sdiobridge_ioctl_setFuncfocus(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
93 {
94     int retval =0;
95     if ( pcmd_data->out_data_len < 0)
96     {
97         retval = -EFAULT;
98         dev_err(glue->dev, "%s : input length must < 0",__FUNCTION__);
99     }
100     else
101     {
102         if ( isCompat )
103         {
104             CHECK_RET(copy_from_user(&glue->funcFocus,(int __user *)compat_ptr((unsigned long)pcmd_data->in_data),sizeof(glue->funcFocus)));
105         }
106         else
107         {
108             CHECK_RET(copy_from_user(&glue->funcFocus,(int __user *)pcmd_data->in_data,sizeof(glue->funcFocus)));
109         }
110     }
111     return retval;
112 }
ssv_sdiobridge_ioctl_getBusWidth(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)113 static long ssv_sdiobridge_ioctl_getBusWidth(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
114 {
115     struct sdio_func *func = dev_to_sdio_func(glue->dev);
116     long retval =0;
117     if ( pcmd_data->out_data_len < 1)
118     {
119         retval = -1;
120     }
121     else
122     {
123         u8 out_data = 1;
124         if ( func->card->host->ios.bus_width != MMC_BUS_WIDTH_1 )
125         {
126             out_data = 4;
127         }
128         if ( isCompat )
129         {
130             CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),&out_data,sizeof(out_data)));
131         }
132         else
133         {
134             CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,&out_data,sizeof(out_data)));
135         }
136     }
137     return retval;
138 }
139 #if 0
140 static long ssv_sdiobridge_ioctl_setBusWidth(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
141 {
142     struct sdio_func *func = dev_to_sdio_func(glue->dev);
143     int retval =0;
144     struct ssv_sdiobridge_cmd *pData;
145     u8 inData[1];
146     copy_from_user(pData,(int __user *)arg,sizeof(*pData));
147     if ( isCompat )
148     {
149         copy_from_user(&cmd_data,(int __user *)compat_ptr((unsigned long)pucmd_data),sizeof(*pucmd_data));
150     }
151     else
152     {
153         copy_from_user(&cmd_data,(int __user *)pucmd_data,sizeof(*pucmd_data));
154     }
155     if ( pData->in_data_len < 0)
156     {
157         retval = -EFAULT;
158         dev_err(glue->dev, "%s : input length must > 1",__FUNCTION__);
159     }
160     else
161     {
162         if ( pData->in_data == 1 )
163         {
164             if ( (func->card->host->caps & MMC_CAP_4_BIT_DATA) && !(func->card->cccr.low_speed && !func->card->cccr.wide_bus) )
165             {
166                 extern void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
167                 u8 ctrl = sdio_f0_readb(func,SDIO_CCCR_IF,&retval);
168                 if (retval)
169                     return retval;
170                 if (!(ctrl & SDIO_BUS_WIDTH_4BIT))
171                     return 0;
172                 ctrl &= ~SDIO_BUS_WIDTH_4BIT;
173                 ctrl |= SDIO_BUS_ASYNC_INT;
174                 sdio_f0_writeb(func,ctrl,SDIO_CCCR_IF,&retval);
175                 if (retval)
176                     return retval;
177                 mmc_set_bus_width(func->card->host, MMC_BUS_WIDTH_1);
178             }
179         }
180         else
181         {
182             if ( func->card->host->ios.bus_width != MMC_BUS_WIDTH_4 )
183             {
184             }
185         }
186     }
187     return retval;
188 }
189 static long ssv_sdiobridge_ioctl_getBlockMode(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
190 {
191     long retval =0;
192     if ( pcmd_data->out_data_len < 1)
193     {
194         retval = -1;
195     }
196     else
197     {
198         if ( isCompat )
199         {
200             copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),&out_data,sizeof(out_data));
201         }
202         else
203         {
204             copy_to_user((int __user *)pucmd_data->out_data,&out_data,sizeof(out_data));
205         }
206     }
207     return retval;
208 }
209 static long ssv_sdiobridge_ioctl_setBlockMode(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
210 {
211     long retval =0;
212     if ( pcmd_data->in_data_len < 1)
213     {
214         retval = -1;
215     }
216     else
217     {
218         if ( isCompat )
219         {
220             copy_from_user(&glue->blockMode,(int __user *)pucmd_data->in_data,sizeof(glue->blockMode));
221         }
222     }
223     return retval;
224 }
225 #endif
ssv_sdiobridge_ioctl_getBlockSize(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)226 static long ssv_sdiobridge_ioctl_getBlockSize(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
227 {
228     long retval =0;
229     if ( pcmd_data->out_data_len < 2)
230     {
231         retval = -1;
232     }
233     else
234     {
235         if ( isCompat )
236         {
237             CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),&glue->blockSize,sizeof(glue->blockSize)));
238         }
239         else
240         {
241             CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,&glue->blockSize,sizeof(glue->blockSize)));
242         }
243     }
244     return retval;
245 }
ssv_sdiobridge_ioctl_setBlockSize(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)246 static long ssv_sdiobridge_ioctl_setBlockSize(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
247 {
248     struct sdio_func *func = dev_to_sdio_func(glue->dev);
249     long retval =0;
250     if ( pcmd_data->in_data_len < 2)
251     {
252         retval = -1;
253     }
254     else
255     {
256         if ( isCompat )
257         {
258             CHECK_RET(copy_from_user(&glue->blockSize,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(glue->blockSize)));
259         }
260         else
261         {
262             CHECK_RET(copy_from_user(&glue->blockSize,(int __user *)pucmd_data->in_data,sizeof(glue->blockSize)));
263         }
264         dev_err(glue->dev,"%s: blockSize [%d]\n",__FUNCTION__,glue->blockSize);
265         sdio_claim_host(func);
266         sdio_set_block_size(func,glue->blockSize);
267         sdio_release_host(func);
268     }
269     return retval;
270 }
ssv_sdiobridge_ioctl_readByte(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)271 static long ssv_sdiobridge_ioctl_readByte(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
272 {
273     struct sdio_func *func = dev_to_sdio_func(glue->dev);
274     long retval =0;
275     if ( pcmd_data->out_data_len < 4)
276     {
277         retval = -1;
278     }
279     else
280     {
281         u32 address;
282         u8 out_data;
283         int ret = 0;
284         if ( isCompat )
285         {
286             CHECK_RET(copy_from_user(&address,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(address)));
287         }
288         else
289         {
290             CHECK_RET(copy_from_user(&address,(int __user *)pucmd_data->in_data,sizeof(address)));
291         }
292         sdio_claim_host(func);
293         if ( glue->funcFocus == 0 )
294         {
295             out_data = sdio_f0_readb(func, address, &ret);
296         }
297         else
298         {
299             out_data = sdio_readb(func, address, &ret);
300         }
301         sdio_release_host(func);
302         dev_err(glue->dev,"%s: [%X] [%02X] ret:[%d]\n",__FUNCTION__,address,out_data,ret);
303         if ( !ret )
304         {
305             if ( isCompat )
306             {
307                 CHECK_RET(copy_to_user((void *)compat_ptr((unsigned long)pucmd_data->out_data),&out_data,sizeof(out_data)));
308             }
309             else
310             {
311                 CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,&out_data,sizeof(out_data)));
312             }
313         }
314         else
315         {
316             dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
317             retval = -1;
318         }
319     }
320     return retval;
321 }
ssv_sdiobridge_ioctl_writeByte(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)322 static long ssv_sdiobridge_ioctl_writeByte(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
323 {
324     struct sdio_func *func = dev_to_sdio_func(glue->dev);
325     long retval =0;
326     if ( pcmd_data->in_data_len < 5)
327     {
328         retval = -1;
329     }
330     else
331     {
332         u8 tmp[5];
333         u32 address;
334         u8 data;
335         int ret = 0;
336         if ( isCompat )
337         {
338             CHECK_RET(copy_from_user(tmp,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(tmp)));
339         }
340         else
341         {
342             CHECK_RET(copy_from_user(tmp,(int __user *)pucmd_data->in_data,sizeof(tmp)));
343         }
344         address = *((u32 *)tmp);
345         data = tmp[4];
346         sdio_claim_host(func);
347         if ( glue->funcFocus == 0 )
348         {
349             sdio_f0_writeb(func,data, address, &ret);
350         }
351         else
352         {
353             sdio_writeb(func,data, address, &ret);
354         }
355         sdio_release_host(func);
356         if ( ret )
357         {
358             dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
359             retval = -1;
360         }
361     }
362     return retval;
363 }
ssv_sdiobridge_ioctl_getMultiByteIOPort(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)364 static long ssv_sdiobridge_ioctl_getMultiByteIOPort(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
365 {
366     long retval =0;
367     if ( pcmd_data->out_data_len < 4)
368     {
369         retval = -1;
370     }
371     else
372     {
373         if ( isCompat )
374         {
375             CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),&glue->dataIOPort,sizeof(glue->dataIOPort)));
376         }
377         else
378         {
379             CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,&glue->dataIOPort,sizeof(glue->dataIOPort)));
380         }
381     }
382     return retval;
383 }
ssv_sdiobridge_ioctl_setMultiByteIOPort(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)384 static long ssv_sdiobridge_ioctl_setMultiByteIOPort(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
385 {
386     long retval =0;
387     if ( pcmd_data->in_data_len < 4)
388     {
389         retval = -1;
390     }
391     else
392     {
393         if ( isCompat )
394         {
395             CHECK_RET(copy_from_user(&glue->dataIOPort,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(glue->dataIOPort)));
396         }
397         else
398         {
399             CHECK_RET(copy_from_user(&glue->dataIOPort,(int __user *)pucmd_data->in_data,sizeof(glue->dataIOPort)));
400         }
401     }
402     return retval;
403 }
ssv_sdiobridge_ioctl_readMultiByte(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)404 static long ssv_sdiobridge_ioctl_readMultiByte(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
405 {
406     struct sdio_func *func = dev_to_sdio_func(glue->dev);
407     long retval =0;
408     u8 *tmpdata;
409     int ret;
410     int readsize;
411     tmpdata = kzalloc(pcmd_data->out_data_len, GFP_KERNEL);
412     if ( tmpdata == NULL )
413     {
414         dev_err(glue->dev,"%s: error : alloc buf error size:%d",__FUNCTION__,pcmd_data->out_data_len);
415         return -1;
416     }
417     readsize = sdio_align_size(func,pcmd_data->out_data_len);
418     sdio_claim_host(func);
419     ret = sdio_memcpy_fromio(func, tmpdata,glue->dataIOPort, readsize );
420     sdio_release_host(func);
421     if (unlikely(glue->dump))
422     {
423         printk(KERN_DEBUG "%s: READ data address[%08x] len[%d] readsize[%d]\n",__FUNCTION__,glue->dataIOPort,(int)pcmd_data->out_data_len,readsize);
424         print_hex_dump(KERN_DEBUG, "ssv_sdio: READ ",
425                        DUMP_PREFIX_OFFSET, 16, 1,
426                        tmpdata, pcmd_data->out_data_len, false);
427     }
428     if ( !ret )
429     {
430         if ( isCompat )
431         {
432             CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),tmpdata,pcmd_data->out_data_len));
433         }
434         else
435         {
436             CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,tmpdata,pcmd_data->out_data_len));
437         }
438     }
439     else
440     {
441         dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
442         retval = -1;
443     }
444     kfree(tmpdata);
445     dev_err(glue->dev,"%s(): %d\n", __FUNCTION__, ret);
446     return retval;
447 }
ssv_sdiobridge_ioctl_writeMultiByte(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)448 static long ssv_sdiobridge_ioctl_writeMultiByte(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
449 {
450     struct sdio_func *func = dev_to_sdio_func(glue->dev);
451     long retval =0;
452     u8 *tmpdata;
453     int ret;
454     int readsize ;
455     tmpdata = kzalloc(pcmd_data->in_data_len, GFP_KERNEL);
456     if ( tmpdata == NULL )
457     {
458         dev_err(glue->dev,"%s: error : alloc buf error size:%d",__FUNCTION__,pcmd_data->out_data_len);
459         return -1;
460     }
461     if ( isCompat )
462     {
463         CHECK_RET(copy_from_user(tmpdata,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),pcmd_data->in_data_len));
464     }
465     else
466     {
467         CHECK_RET(copy_from_user(tmpdata,(int __user *)pucmd_data->in_data,pcmd_data->in_data_len));
468     }
469     readsize = sdio_align_size(func,pcmd_data->in_data_len);
470     if (unlikely(glue->dump))
471     {
472         printk(KERN_DEBUG "%s: READ data address[%08x] len[%d] readsize[%d]\n",__FUNCTION__,glue->dataIOPort,(int)pcmd_data->in_data_len,readsize);
473         print_hex_dump(KERN_DEBUG, "ssv_sdio: WRITE ",
474                        DUMP_PREFIX_OFFSET, 16, 1,
475                        tmpdata, pcmd_data->in_data_len, false);
476     }
477     sdio_claim_host(func);
478     ret = sdio_memcpy_toio(func, glue->dataIOPort,tmpdata, readsize);
479     sdio_release_host(func);
480     if ( ret )
481     {
482         dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
483         retval = -1;
484     }
485     kfree(tmpdata);
486     return retval;
487 }
ssv_sdiobridge_ioctl_getMultiByteRegIOPort(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)488 static long ssv_sdiobridge_ioctl_getMultiByteRegIOPort(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
489 {
490     long retval =0;
491     if ( pcmd_data->out_data_len < 4)
492     {
493         retval = -1;
494     }
495     else
496     {
497         if ( isCompat )
498         {
499             CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),&glue->regIOPort,sizeof(glue->regIOPort)));
500         }
501         else
502         {
503             CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,&glue->regIOPort,sizeof(glue->regIOPort)));
504         }
505     }
506     return retval;
507 }
ssv_sdiobridge_ioctl_setMultiByteRegIOPort(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)508 static long ssv_sdiobridge_ioctl_setMultiByteRegIOPort(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
509 {
510     long retval =0;
511     if ( pcmd_data->in_data_len < 4)
512     {
513         retval = -1;
514     }
515     else
516     {
517         if ( isCompat )
518         {
519             CHECK_RET(copy_from_user(&glue->regIOPort,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(glue->regIOPort)));
520         }
521         else
522         {
523             CHECK_RET(copy_from_user(&glue->regIOPort,(int __user *)pucmd_data->in_data,sizeof(glue->regIOPort)));
524         }
525     }
526     return retval;
527 }
ssv_sdiobridge_ioctl_readReg(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)528 static long ssv_sdiobridge_ioctl_readReg(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
529 {
530     struct sdio_func *func = dev_to_sdio_func(glue->dev);
531     long retval =0;
532     if ( pcmd_data->in_data_len < 4 || pcmd_data->out_data_len < 4)
533     {
534         retval = -1;
535     }
536     else
537     {
538         u8 tmpdata[4];
539         int ret = 0;
540         if ( isCompat )
541         {
542             CHECK_RET(copy_from_user(tmpdata,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(tmpdata)));
543         }
544         else
545         {
546             CHECK_RET(copy_from_user(tmpdata,(int __user *)pucmd_data->in_data,sizeof(tmpdata)));
547         }
548         sdio_claim_host(func);
549         dev_err(glue->dev,"%s: read reg 1 [%02X][%02X][%02X][%02X]\n",__FUNCTION__,tmpdata[0],tmpdata[1],tmpdata[2],tmpdata[3]);
550         ret = sdio_memcpy_toio(func, glue->regIOPort, tmpdata, 4);
551         ret = sdio_memcpy_fromio(func, tmpdata, glue->regIOPort, 4);
552         sdio_release_host(func);
553         dev_err(glue->dev,"%s: read reg 2 [%02X][%02X][%02X][%02X] ret:%d\n",__FUNCTION__,tmpdata[0],tmpdata[1],tmpdata[2],tmpdata[3],ret);
554         if ( !ret )
555         {
556             if ( isCompat )
557             {
558                 CHECK_RET(copy_to_user((int __user *)compat_ptr((unsigned long)pucmd_data->out_data),tmpdata,sizeof(tmpdata)));
559             }
560             else
561             {
562                 CHECK_RET(copy_to_user((int __user *)pucmd_data->out_data,tmpdata,sizeof(tmpdata)));
563             }
564         }
565         else
566         {
567             dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
568             retval = -1;
569         }
570     }
571     return retval;
572 }
ssv_sdiobridge_ioctl_writeReg(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pcmd_data,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)573 static long ssv_sdiobridge_ioctl_writeReg(struct ssv_sdiobridge_glue *glue,unsigned int cmd, struct ssv_sdiobridge_cmd *pcmd_data,struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
574 {
575     struct sdio_func *func = dev_to_sdio_func(glue->dev);
576     long retval =0;
577     if ( pcmd_data->in_data_len < 8)
578     {
579         retval = -1;
580     }
581     else
582     {
583         u8 tmpdata[8];
584         int ret = 0;
585         if ( isCompat )
586         {
587             CHECK_RET(copy_from_user(tmpdata,(int __user *)compat_ptr((unsigned long)pucmd_data->in_data),sizeof(tmpdata)));
588         }
589         else
590         {
591             CHECK_RET(copy_from_user(tmpdata,(int __user *)pucmd_data->in_data,sizeof(tmpdata)));
592         }
593         dev_err(glue->dev,"%s: write reg ADR[%02X%02X%02X%02X] [%02X][%02X][%02X][%02X]\n",__FUNCTION__,tmpdata[3],tmpdata[2],tmpdata[1],tmpdata[0],
594             tmpdata[7], tmpdata[6], tmpdata[5], tmpdata[4]);
595         sdio_claim_host(func);
596         ret = sdio_memcpy_toio(func, glue->regIOPort, tmpdata, 8);
597         sdio_release_host(func);
598         if ( ret )
599         {
600             dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
601             retval = -1;
602         }
603     }
604     return retval;
605 }
ssv_sdiobridge_device_open(struct inode * inode,struct file * filp)606 static int ssv_sdiobridge_device_open(struct inode *inode, struct file *filp)
607 {
608     dev_err(glue->dev,"%s():\n", __FUNCTION__);
609     filp->private_data = glue;
610     return 0;
611 }
ssv_sdiobridge_device_close(struct inode * inode,struct file * filp)612 static int ssv_sdiobridge_device_close(struct inode *inode, struct file *filp)
613 {
614     dev_err(glue->dev,"%s():\n", __FUNCTION__);
615     return 0;
616 }
ssv_sdiobridge_device_ioctl_process(struct ssv_sdiobridge_glue * glue,unsigned int cmd,struct ssv_sdiobridge_cmd * pucmd_data,bool isCompat)617 static long ssv_sdiobridge_device_ioctl_process(struct ssv_sdiobridge_glue *glue, unsigned int cmd, struct ssv_sdiobridge_cmd *pucmd_data,bool isCompat)
618 {
619     struct ssv_sdiobridge_cmd cmd_data;
620     long retval=0;
621     if ( isCompat )
622     {
623         CHECK_RET(copy_from_user(&cmd_data,(int __user *)pucmd_data,sizeof(*pucmd_data)));
624     }
625     else
626     {
627         CHECK_RET(copy_from_user(&cmd_data,(int __user *)pucmd_data,sizeof(*pucmd_data)));
628     }
629 #if 0
630 #ifdef __x86_64
631     dev_err(glue->dev,"%s: isCompat[%d] [%lX] [%lX] [%X] \n",__FUNCTION__,isCompat,IOCTL_SSVSDIO_GET_FUNCTION_FOCUS,IOCTL_SSVSDIO_READ_DATA,cmd);
632 #else
633     dev_err(glue->dev,"%s: isCompat[%d] [%X] [%X] [%X] \n",__FUNCTION__,isCompat,IOCTL_SSVSDIO_GET_FUNCTION_FOCUS,IOCTL_SSVSDIO_READ_DATA,cmd);
634 #endif
635 #endif
636     switch (cmd)
637     {
638         case IOCTL_SSVSDIO_GET_FUNCTION_FOCUS:
639             retval = ssv_sdiobridge_ioctl_getFuncfocus(glue,cmd,&cmd_data,pucmd_data,isCompat);
640             break;
641         case IOCTL_SSVSDIO_SET_FUNCTION_FOCUS:
642             retval = ssv_sdiobridge_ioctl_setFuncfocus(glue,cmd,&cmd_data,pucmd_data,isCompat);
643             break;
644         case IOCTL_SSVSDIO_GET_BUS_WIDTH:
645             retval = ssv_sdiobridge_ioctl_getBusWidth(glue,cmd,&cmd_data,pucmd_data,isCompat);
646             break;
647 #if 0
648         case IOCTL_SSVSDIO_SET_BUS_WIDTH:
649             retval = ssv_sdiobridge_ioctl_setBusWidth(glue,cmd,&cmd_data,pucmd_data,isCompat);
650             break;
651         case IOCTL_SSVSDIO_GET_BUS_CLOCK:
652             break;
653         case IOCTL_SSVSDIO_SET_BUS_CLOCK:
654             break;
655         case IOCTL_SSVSDIO_GET_BLOCK_MODE:
656             retval = ssv_sdiobridge_ioctl_getBlockMode(glue,cmd,&cmd_data,pucmd_data,isCompat);
657             break;
658         case IOCTL_SSVSDIO_SET_BLOCK_MODE:
659             retval = ssv_sdiobridge_ioctl_setBlockMode(glue,cmd,&cmd_data,pucmd_data,isCompat);
660             break;
661 #endif
662         case IOCTL_SSVSDIO_GET_BLOCKLEN:
663             retval = ssv_sdiobridge_ioctl_getBlockSize(glue,cmd,&cmd_data,pucmd_data,isCompat);
664             break;
665         case IOCTL_SSVSDIO_SET_BLOCKLEN:
666             retval = ssv_sdiobridge_ioctl_setBlockSize(glue,cmd,&cmd_data,pucmd_data,isCompat);
667             break;
668         case IOCTL_SSVSDIO_READ_BYTE:
669             retval = ssv_sdiobridge_ioctl_readByte(glue,cmd,&cmd_data,pucmd_data,isCompat);
670             break;
671         case IOCTL_SSVSDIO_WRITE_BYTE:
672             retval = ssv_sdiobridge_ioctl_writeByte(glue,cmd,&cmd_data,pucmd_data,isCompat);
673             break;
674         case IOCTL_SSVSDIO_GET_MULTI_BYTE_IO_PORT:
675             retval = ssv_sdiobridge_ioctl_getMultiByteIOPort(glue,cmd,&cmd_data,pucmd_data,isCompat);
676             break;
677         case IOCTL_SSVSDIO_SET_MULTI_BYTE_IO_PORT:
678             retval = ssv_sdiobridge_ioctl_setMultiByteIOPort(glue,cmd,&cmd_data,pucmd_data,isCompat);
679             break;
680         case IOCTL_SSVSDIO_READ_MULTI_BYTE:
681             retval = ssv_sdiobridge_ioctl_readMultiByte(glue,cmd,&cmd_data,pucmd_data,isCompat);
682             break;
683         case IOCTL_SSVSDIO_WRITE_MULTI_BYTE:
684             retval = ssv_sdiobridge_ioctl_writeMultiByte(glue,cmd,&cmd_data,pucmd_data,isCompat);
685             break;
686         case IOCTL_SSVSDIO_GET_MULTI_BYTE_REG_IO_PORT:
687             retval = ssv_sdiobridge_ioctl_getMultiByteRegIOPort(glue,cmd,&cmd_data,pucmd_data,isCompat);
688             break;
689         case IOCTL_SSVSDIO_SET_MULTI_BYTE_REG_IO_PORT:
690             retval = ssv_sdiobridge_ioctl_setMultiByteRegIOPort(glue,cmd,&cmd_data,pucmd_data,isCompat);
691             break;
692         case IOCTL_SSVSDIO_READ_REG:
693             retval = ssv_sdiobridge_ioctl_readReg(glue,cmd,&cmd_data,pucmd_data,isCompat);
694             break;
695         case IOCTL_SSVSDIO_WRITE_REG:
696             retval = ssv_sdiobridge_ioctl_writeReg(glue,cmd,&cmd_data,pucmd_data,isCompat);
697             break;
698     }
699     return retval;
700 }
ssv_sdiobridge_device_compat_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)701 static long ssv_sdiobridge_device_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
702 {
703     struct ssv_sdiobridge_glue *glue =filp->private_data;
704     long retval=0;
705     struct ssv_sdiobridge_cmd *pucmd_data;
706     pucmd_data = (struct ssv_sdiobridge_cmd *)arg;
707     retval = ssv_sdiobridge_device_ioctl_process( glue,cmd,pucmd_data,true);
708     return retval;
709 }
ssv_sdiobridge_device_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)710 static long ssv_sdiobridge_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
711 {
712     struct ssv_sdiobridge_glue *glue =filp->private_data;
713     long retval=0;
714     struct ssv_sdiobridge_cmd *pucmd_data;
715     pucmd_data = (struct ssv_sdiobridge_cmd *)arg;
716     retval = ssv_sdiobridge_device_ioctl_process( glue,cmd,pucmd_data,false);
717     return retval;
718 }
ssv_sdiobridge_have_data(struct ssv_sdiobridge_glue * glue)719 static bool ssv_sdiobridge_have_data(struct ssv_sdiobridge_glue *glue)
720 {
721     dev_err(glue->dev,"%s(): !list_empty(&glue->rxreadybuf)[%d]\n", __FUNCTION__,!list_empty(&glue->rxreadybuf));
722     return !list_empty(&glue->rxreadybuf);
723 }
ssv_sdiobridge_device_read(struct file * filp,char * buffer,size_t length,loff_t * offset)724 static ssize_t ssv_sdiobridge_device_read(struct file *filp,
725         char *buffer,
726         size_t length,
727         loff_t *offset)
728 {
729     struct ssv_sdiobridge_glue *glue =filp->private_data;
730     struct ssv_rxbuf *bf;
731     int copylength;
732     dev_err(glue->dev,"%s():\n", __FUNCTION__);
733     spin_lock_bh(&glue->rxbuflock);
734     if (list_empty(&glue->rxreadybuf))
735     {
736         spin_unlock_bh(&glue->rxbuflock);
737         dev_err(glue->dev,"%s():no data for read \n", __FUNCTION__);
738 #if 1
739         if ( wait_event_interruptible(glue->read_wq, ssv_sdiobridge_have_data(glue))!=0)
740         {
741             dev_err(glue->dev,"%s():not get data ?? \n", __FUNCTION__);
742             return -1;
743         }
744 #else
745         wait_event(glue->read_wq,ssv_sdiobridge_have_data(glue));
746 #endif
747         spin_lock_bh(&glue->rxbuflock);
748         if (list_empty(&glue->rxreadybuf))
749         {
750             spin_unlock_bh(&glue->rxbuflock);
751             dev_err(glue->dev,"%s():stop ?? \n", __FUNCTION__);
752             return -1;
753         }
754     }
755     bf = list_first_entry(&glue->rxreadybuf, struct ssv_rxbuf, list);
756     list_del(&bf->list);
757     spin_unlock_bh(&glue->rxbuflock);
758     copylength = min(bf->rxsize,(u32)length);
759     CHECK_RET(copy_to_user((int __user *)buffer,bf->rxdata,copylength));
760     dev_err(glue->dev,"%s():get rx data : data len:[%d], user read len:[%d],real read len:[%d] \n", __FUNCTION__,bf->rxsize,(u32)length,copylength);
761     spin_lock_bh(&glue->rxbuflock);
762     list_add_tail(&bf->list, &glue->rxbuf);
763     spin_unlock_bh(&glue->rxbuflock);
764     return copylength;
765 }
ssv_sdiobridge_device_write(struct file * filp,const char * buff,size_t len,loff_t * off)766 static ssize_t ssv_sdiobridge_device_write(struct file *filp,
767         const char *buff,
768         size_t len,
769         loff_t *off)
770 {
771     struct ssv_sdiobridge_glue *glue =filp->private_data;
772     struct sdio_func *func = dev_to_sdio_func(glue->dev);
773     u8 *tmpdata;
774     int ret;
775     dev_err(glue->dev,"%s():\n", __FUNCTION__);
776     tmpdata = kzalloc(len, GFP_KERNEL);
777     if ( tmpdata == NULL )
778     {
779         dev_err(glue->dev,"%s: error : alloc buf error size:%d",__FUNCTION__,(u32)len);
780         return -1;
781     }
782     CHECK_RET(copy_from_user(tmpdata,(int __user *)buff,len));
783     if (unlikely(glue->dump))
784     {
785         printk(KERN_DEBUG "%s: WRITE data address[%08x] len[%d] readsize[%d]\n",__FUNCTION__,glue->dataIOPort,(int)len,sdio_align_size(func,len));
786         print_hex_dump(KERN_DEBUG, "ssv_sdio: WRITE ",
787                        DUMP_PREFIX_OFFSET, 16, 1,
788                        tmpdata, len, false);
789     }
790     sdio_claim_host(func);
791     ret = sdio_memcpy_toio(func, glue->dataIOPort,tmpdata, sdio_align_size(func,len));
792     sdio_release_host(func);
793     kfree(tmpdata);
794     if ( ret )
795     {
796         dev_err(glue->dev,"%s: error : %d",__FUNCTION__,ret);
797         return -1;
798     }
799     return len;
800 }
801 struct file_operations fops =
802 {
803     .owner = THIS_MODULE,
804     .read = ssv_sdiobridge_device_read,
805     .write = ssv_sdiobridge_device_write,
806     .open = ssv_sdiobridge_device_open,
807     .release = ssv_sdiobridge_device_close,
808     .compat_ioctl = ssv_sdiobridge_device_compat_ioctl,
809     .unlocked_ioctl = ssv_sdiobridge_device_ioctl
810 };
ssv_sdiobridge_irq_process(struct sdio_func * func,struct ssv_sdiobridge_glue * glue)811 static void ssv_sdiobridge_irq_process(struct sdio_func *func,
812                                        struct ssv_sdiobridge_glue *glue)
813 {
814     int err_ret;
815     u8 status;
816     sdio_claim_host(func);
817     status = sdio_readb(func, REG_INT_STATUS, &err_ret);
818     if ( status & SSVCABRIO_INT_RX )
819     {
820         struct ssv_rxbuf *bf;
821         int readsize;
822         spin_lock_bh(&glue->rxbuflock);
823         if (list_empty(&glue->rxbuf))
824         {
825             spin_unlock_bh(&glue->rxbuflock);
826             sdio_release_host(func);
827             dev_err(glue->dev, "ssv_sdiobridge_irq_process no avaible rx buf list??\n");
828             return;
829         }
830         else
831         {
832             bf = list_first_entry(&glue->rxbuf, struct ssv_rxbuf, list);
833             list_del(&bf->list);
834         }
835         spin_unlock_bh(&glue->rxbuflock);
836         bf->rxsize = (int)(sdio_readb(func, REG_CARD_PKT_LEN_0, &err_ret)&0xff);
837         dev_err(glue->dev, "sdio read rx size[%08x] 0x10[%02x]\n",bf->rxsize, sdio_readb(func, REG_CARD_PKT_LEN_0, &err_ret)&0xff);
838         bf->rxsize = bf->rxsize | ((sdio_readb(func, REG_CARD_PKT_LEN_1, &err_ret)&0xff)<<0x8);
839         readsize = sdio_align_size(func,bf->rxsize);
840         dev_err(glue->dev, "sdio read rx size[%08x] 0x11[%02x] readsize[%d]\n",bf->rxsize, sdio_readb(func, REG_CARD_PKT_LEN_1, &err_ret)&0xff,readsize);
841         err_ret = sdio_memcpy_fromio(func, bf->rxdata, glue->dataIOPort, readsize);
842         sdio_release_host(func);
843         dev_err(glue->dev, "ssv_sdiobridge_irq_process read 53, %d bytes  ret:[%d]\n", readsize,err_ret );
844         if (unlikely(glue->dump))
845         {
846             printk(KERN_DEBUG "ssv_sdiobridge_irq_process: READ data address[%08x] len[%d] readsize[%d]\n",glue->dataIOPort,(int)bf->rxsize,readsize);
847             print_hex_dump(KERN_DEBUG, "ssv_sdio: READ ",
848                            DUMP_PREFIX_OFFSET, 16, 1,
849                            bf->rxdata, bf->rxsize, false);
850         }
851         if (WARN_ON(err_ret))
852         {
853             dev_err(glue->dev, "ssv_sdiobridge_irq_process read failed (%d)\n", err_ret);
854             spin_lock_bh(&glue->rxbuflock);
855             list_add_tail(&bf->list, &glue->rxbuf);
856             spin_unlock_bh(&glue->rxbuflock);
857         }
858         else
859         {
860             spin_lock_bh(&glue->rxbuflock);
861             list_add_tail(&bf->list, &glue->rxreadybuf);
862             wake_up(&glue->read_wq);
863             spin_unlock_bh(&glue->rxbuflock);
864         }
865     }
866     else
867     {
868         sdio_release_host(func);
869     }
870 }
ssv_sdiobridge_irq_handler(struct sdio_func * func)871 static void ssv_sdiobridge_irq_handler(struct sdio_func *func)
872 {
873     struct ssv_sdiobridge_glue *glue = sdio_get_drvdata(func);
874     dev_err(&func->dev, "ssv_sdiobridge_irq_handler\n");
875     WARN_ON(glue == NULL);
876     if ( glue != NULL )
877     {
878         atomic_set(&glue->irq_handling, 1);
879         ssv_sdiobridge_irq_process(func,glue);
880         atomic_set(&glue->irq_handling, 0);
881         wake_up(&glue->irq_wq);
882     }
883 }
ssv_sdiobridge_irq_enable(struct sdio_func * func,struct ssv_sdiobridge_glue * glue)884 static void ssv_sdiobridge_irq_enable(struct sdio_func *func,
885                                       struct ssv_sdiobridge_glue *glue)
886 {
887     int ret;
888     func = dev_to_sdio_func(glue->dev);
889     sdio_claim_host(func);
890     dev_err(glue->dev, "ssv_sdiobridge_irq_enable\n");
891     ret = sdio_claim_irq(func, ssv_sdiobridge_irq_handler);
892     if (ret)
893         dev_err(glue->dev, "Failed to claim sdio irq: %d\n", ret);
894     sdio_release_host(func);
895 }
ssv_sdiobridge_is_on_irq(struct ssv_sdiobridge_glue * glue)896 static bool ssv_sdiobridge_is_on_irq(struct ssv_sdiobridge_glue *glue)
897 {
898     return !atomic_read(&glue->irq_handling);
899 }
ssv_sdiobridge_irq_disable(struct ssv_sdiobridge_glue * glue,bool iswaitirq)900 static void ssv_sdiobridge_irq_disable(struct ssv_sdiobridge_glue *glue,bool iswaitirq)
901 {
902     struct sdio_func *func;
903     int ret;
904     dev_err(glue->dev, "ssv_sdiobridge_irq_disable1\n");
905     if ( glue != NULL )
906     {
907         func = dev_to_sdio_func(glue->dev);
908         sdio_claim_host(func);
909         dev_err(glue->dev, "ssv_sdiobridge_irq_disable2 [%d]\n",atomic_read(&glue->irq_handling));
910         if (atomic_read(&glue->irq_handling)&&iswaitirq)
911         {
912             dev_err(glue->dev, "ssv_sdiobridge_irq_disable3\n");
913             sdio_release_host(func);
914             ret = wait_event_interruptible(glue->irq_wq,
915                                            ssv_sdiobridge_is_on_irq(glue));
916             dev_err(glue->dev, "ssv_sdiobridge_irq_disable4 ret[%d]\n",ret);
917             if (ret)
918                 return;
919             sdio_claim_host(func);
920         }
921         dev_err(glue->dev, "ssv_sdiobridge_irq_disable5\n");
922         ret = sdio_release_irq(func);
923         if (ret)
924             dev_err(glue->dev, "Failed to release sdio irq: %d\n", ret);
925         dev_err(glue->dev, "ssv_sdiobridge_irq_disable6\n");
926         sdio_release_host(func);
927     }
928 }
929 #if 0
930 static void ssv_sdiobridge_irq_sync(struct device *child)
931 {
932     struct ssv_sdiobridge_glue *glue = dev_get_drvdata(child->parent);
933     struct sdio_func *func;
934     int ret;
935     if ( glue != NULL )
936     {
937         func = dev_to_sdio_func(glue->dev);
938         sdio_claim_host(func);
939         if (atomic_read(&glue->irq_handling))
940         {
941             sdio_release_host(func);
942             ret = wait_event_interruptible(glue->irq_wq,
943                                            ssv_sdiobridge_is_on_irq(glue));
944             if (ret)
945                 return;
946             sdio_claim_host(func);
947         }
948         sdio_release_host(func);
949     }
950 }
951 #endif
ssv_sdiobridge_read_parameter(struct sdio_func * func,struct ssv_sdiobridge_glue * glue)952 static void ssv_sdiobridge_read_parameter(struct sdio_func *func,
953         struct ssv_sdiobridge_glue *glue)
954 {
955     int err_ret;
956     sdio_claim_host(func);
957     glue->dataIOPort = 0;
958     glue->dataIOPort = glue->dataIOPort | (sdio_readb(func, REG_DATA_IO_PORT_0, &err_ret) << ( 8*0 ));
959     glue->dataIOPort = glue->dataIOPort | (sdio_readb(func, REG_DATA_IO_PORT_1, &err_ret) << ( 8*1 ));
960     glue->dataIOPort = glue->dataIOPort | (sdio_readb(func, REG_DATA_IO_PORT_2, &err_ret) << ( 8*2 ));
961     glue->regIOPort = 0;
962     glue->regIOPort = glue->regIOPort | (sdio_readb(func, REG_REG_IO_PORT_0, &err_ret) << ( 8*0 ));
963     glue->regIOPort = glue->regIOPort | (sdio_readb(func, REG_REG_IO_PORT_1, &err_ret) << ( 8*1 ));
964     glue->regIOPort = glue->regIOPort | (sdio_readb(func, REG_REG_IO_PORT_2, &err_ret) << ( 8*2 ));
965     dev_err(&func->dev, "dataIOPort 0x%x regIOPort 0x%x [%lx]\n",
966             glue->dataIOPort,glue->regIOPort,(long unsigned int)IOCTL_SSVSDIO_GET_BLOCKLEN);
967     sdio_set_block_size(func,glue->blockSize);
968     sdio_release_host(func);
969 }
ssv_sdiobridge_init_buf(struct ssv_sdiobridge_glue * glue)970 static int ssv_sdiobridge_init_buf(struct ssv_sdiobridge_glue *glue)
971 {
972     u32 bsize,i,error;
973     struct ssv_rxbuf *bf;
974     init_waitqueue_head(&glue->read_wq);
975     spin_lock_init(&glue->rxbuflock);
976     INIT_LIST_HEAD(&glue->rxbuf);
977     INIT_LIST_HEAD(&glue->rxreadybuf);
978     bsize = sizeof(struct ssv_rxbuf) * RXBUFSIZE;
979     glue->bufaddr = kzalloc(bsize, GFP_KERNEL);
980     if (glue->bufaddr == NULL)
981     {
982         error = -ENOMEM;
983         goto fail;
984     }
985     bf = glue->bufaddr;
986     for (i = 0; i < RXBUFSIZE; i++, bf++)
987     {
988         list_add_tail(&bf->list, &glue->rxbuf);
989     }
990     return 0;
991 fail:
992     return error;
993 }
994 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
ssv_sdiobridge_devnode(struct device * dev,umode_t * mode)995 static char *ssv_sdiobridge_devnode(struct device *dev, umode_t *mode)
996 #else
997 static char *ssv_sdiobridge_devnode(struct device *dev, mode_t *mode)
998 #endif
999 {
1000     if (!mode)
1001         return NULL;
1002     *mode = 0666;
1003     return NULL;
1004 }
1005 extern int ssv_devicetype;
ssv_sdiobridge_probe(struct sdio_func * func,const struct sdio_device_id * id)1006 static int __devinit ssv_sdiobridge_probe(struct sdio_func *func,
1007         const struct sdio_device_id *id)
1008 {
1009     mmc_pm_flag_t mmcflags;
1010     int ret = -ENOMEM;
1011     dev_t dev;
1012     int alloc_ret = 0;
1013     int cdev_ret = 0;
1014     int err_ret;
1015     if (ssv_devicetype != 1) {
1016         printk(KERN_INFO "Not using SSV6200 bridge SDIO driver.\n");
1017         return -ENODEV;
1018     }
1019     printk(KERN_INFO "=======================================\n");
1020     printk(KERN_INFO "==           RUN SDIO BRIDGE         ==\n");
1021     printk(KERN_INFO "=======================================\n");
1022     printk(KERN_INFO "ssv_sdiobridge_probe func->num:%d",func->num);
1023     if (func->num != 0x01)
1024         return -ENODEV;
1025     glue = kzalloc(sizeof(*glue), GFP_KERNEL);
1026     if (!glue)
1027     {
1028         dev_err(&func->dev, "can't allocate glue\n");
1029         goto out;
1030     }
1031     glue->blockMode = false;
1032     glue->blockSize = BLOCKSIZE;
1033     glue->autoAckInt = true;
1034     glue->dump = false;
1035     glue->funcFocus = 1;
1036     ssv_sdiobridge_init_buf(glue);
1037     glue->dev = &func->dev;
1038     func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
1039     func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
1040     mmcflags = sdio_get_host_pm_caps(func);
1041     dev_err(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
1042     sdio_set_drvdata(func, glue);
1043     pm_runtime_put_noidle(&func->dev);
1044     ssv_sdiobridge_read_parameter(func,glue);
1045     dev = MKDEV(ssv_sdiobridge_ioctl_major, 0);
1046     alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, FILE_DEVICE_SSVSDIO_NAME);
1047     if (alloc_ret)
1048         goto error;
1049     ssv_sdiobridge_ioctl_major = MAJOR(dev);
1050     cdev_init(&ssv_sdiobridge_ioctl_cdev, &fops);
1051     cdev_ret = cdev_add(&ssv_sdiobridge_ioctl_cdev, dev, num_of_dev);
1052     if (cdev_ret)
1053         goto error;
1054     fc=class_create(THIS_MODULE, FILE_DEVICE_SSVSDIO_NAME);
1055     fc->devnode = ssv_sdiobridge_devnode;
1056     device_create(fc, NULL, dev, NULL, "%s", FILE_DEVICE_SSVSDIO_NAME);
1057     dev_err(glue->dev, "%s driver(major: %d) installed.\n", FILE_DEVICE_SSVSDIO_NAME, ssv_sdiobridge_ioctl_major);
1058     init_waitqueue_head(&glue->irq_wq);
1059     ssv_sdiobridge_irq_enable(func,glue);
1060     sdio_claim_host(func);
1061 #ifdef CONFIG_SSV_SDIO_EXT_INT
1062     sdio_writeb(func,(~(SSVCABRIO_INT_RX)|SSVCABRIO_INT_GPIO)&0x7, 0x04, &err_ret);
1063 #else
1064     sdio_writeb(func,(~(SSVCABRIO_INT_RX|SSVCABRIO_INT_GPIO))&0x7, 0x04, &err_ret);
1065 #endif
1066     sdio_release_host(func);
1067     return 0;
1068 error:
1069     if (cdev_ret == 0)
1070         cdev_del(&ssv_sdiobridge_ioctl_cdev);
1071     if (alloc_ret == 0)
1072         unregister_chrdev_region(dev, num_of_dev);
1073     kfree(glue);
1074 out:
1075     return ret;
1076 }
ssv_sdiobridge_remove(struct sdio_func * func)1077 static void __devexit ssv_sdiobridge_remove(struct sdio_func *func)
1078 {
1079     struct ssv_sdiobridge_glue *glue = sdio_get_drvdata(func);
1080     dev_t dev;
1081     int err_ret;
1082     sdio_claim_host(func);
1083 #ifdef CONFIG_SSV_SDIO_EXT_INT
1084     sdio_writeb(func,0, 0x04, &err_ret);
1085 #else
1086     sdio_writeb(func,SSVCABRIO_INT_GPIO, 0x04, &err_ret);
1087 #endif
1088     sdio_release_host(func);
1089     ssv_sdiobridge_irq_disable(glue,false);
1090     dev = MKDEV(ssv_sdiobridge_ioctl_major, 0);
1091     device_destroy(fc,dev);
1092     class_destroy(fc);
1093     cdev_del(&ssv_sdiobridge_ioctl_cdev);
1094     unregister_chrdev_region(dev, num_of_dev);
1095     pm_runtime_get_noresume(&func->dev);
1096     if ( glue )
1097     {
1098         dev_err(glue->dev, "ssv_sdiobridge_remove");
1099         if (glue->bufaddr)
1100         {
1101             kfree(glue->bufaddr);
1102         }
1103         kfree(glue);
1104         glue = NULL;
1105     }
1106     sdio_set_drvdata(func, NULL);
1107 }
1108 #ifdef CONFIG_PM
ssv_sdiobridge_suspend(struct device * dev)1109 static int ssv_sdiobridge_suspend(struct device *dev)
1110 {
1111     int ret = 0;
1112     return ret;
1113 }
ssv_sdiobridge_resume(struct device * dev)1114 static int ssv_sdiobridge_resume(struct device *dev)
1115 {
1116     dev_dbg(dev, "ssvcabrio resume\n");
1117     return 0;
1118 }
1119 static const struct dev_pm_ops ssv_sdiobridge_pm_ops =
1120 {
1121     .suspend = ssv_sdiobridge_suspend,
1122     .resume = ssv_sdiobridge_resume,
1123 };
1124 #endif
1125 static struct sdio_driver ssv_sdio_bridge_driver =
1126 {
1127     .name = "ssv_sdio_bridge",
1128     .id_table = ssv_sdiobridge_devices,
1129     .probe = ssv_sdiobridge_probe,
1130     .remove = __devexit_p(ssv_sdiobridge_remove),
1131 #ifdef CONFIG_PM
1132     .drv = {
1133         .pm = &ssv_sdiobridge_pm_ops,
1134     },
1135 #endif
1136 };
1137 EXPORT_SYMBOL(ssv_sdio_bridge_driver);
1138 #if 1
ssv_sdiobridge_init(void)1139 static int __init ssv_sdiobridge_init(void)
1140 {
1141     printk(KERN_INFO "ssv_sdiobridge_init\n");
1142     return sdio_register_driver(&ssv_sdio_bridge_driver);
1143 }
ssv_sdiobridge_exit(void)1144 static void __exit ssv_sdiobridge_exit(void)
1145 {
1146     printk(KERN_INFO "ssv_sdiobridge_exit\n");
1147     sdio_unregister_driver(&ssv_sdio_bridge_driver);
1148 }
1149 module_init(ssv_sdiobridge_init);
1150 module_exit(ssv_sdiobridge_exit);
1151 #endif
1152 MODULE_LICENSE("GPL");
1153 MODULE_AUTHOR("iComm Semiconductor Co., Ltd");
1154