65087cea30280dba6340d90b69d279271c906c5b
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / ft1000 / ft1000-usb / ft1000_chdev.c
1 //---------------------------------------------------------------------------
2 // FT1000 driver for Flarion Flash OFDM NIC Device
3 //
4 // Copyright (C) 2006 Flarion Technologies, All rights reserved.
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License as published by the Free
8 // Software Foundation; either version 2 of the License, or (at your option) any
9 // later version. This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 // more details. You should have received a copy of the GNU General Public
13 // License along with this program; if not, write to the
14 // Free Software Foundation, Inc., 59 Temple Place -
15 // Suite 330, Boston, MA 02111-1307, USA.
16 //---------------------------------------------------------------------------
17 //
18 // File:         ft1000_chdev.c
19 //
20 // Description:  Custom character device dispatch routines.
21 //
22 // History:
23 // 8/29/02    Whc                Ported to Linux.
24 // 6/05/06    Whc                Porting to Linux 2.6.9
25 //
26 //---------------------------------------------------------------------------
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/signal.h>
31 #include <linux/errno.h>
32 #include <linux/poll.h>
33 #include <linux/netdevice.h>
34 #include <linux/delay.h>
35
36 #include <linux/fs.h>
37 #include <linux/kmod.h>
38 #include <linux/ioctl.h>
39 #include <linux/unistd.h>
40
41 #include "ft1000_usb.h"
42 //#include "ft1000_ioctl.h"
43
44 void ft1000_DestroyDevice(struct net_device *dev);
45 u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow);
46 u16 ft1000_read_register(struct ft1000_device *ft1000dev, short* Data, u16 nRegIndx);
47
48 extern inline u16 ft1000_asic_read (struct net_device *dev, u16 offset);
49 extern inline void ft1000_asic_write (struct net_device *dev, u16 offset, u16 value);
50 extern void CardSendCommand(struct ft1000_device *ft1000dev, unsigned short *ptempbuffer, int size);
51
52 static int ft1000_ChOpen (struct inode *Inode, struct file *File);
53 static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait);
54 static int ft1000_ChIoctl(struct file *File, unsigned int Command,
55                            unsigned long Argument);
56 static int ft1000_ChRelease (struct inode *Inode, struct file *File);
57
58 static int ft1000_flarion_cnt = 0;
59
60 //need to looking usage of ft1000Handle
61
62
63
64 // Global pointer to device object
65 static struct ft1000_device *pdevobj[MAX_NUM_CARDS + 2];
66 //static devfs_handle_t ft1000Handle[MAX_NUM_CARDS];
67
68 // List to free receive command buffer pool
69 struct list_head freercvpool;
70
71 // lock to arbitrate free buffer list for receive command data
72 spinlock_t free_buff_lock;
73
74 int numofmsgbuf = 0;
75
76 // Global variable to indicate that all provisioning data is sent to DSP
77 //BOOLEAN fProvComplete;
78
79 //
80 // Table of entry-point routines for char device
81 //
82 static struct file_operations ft1000fops =
83 {
84     unlocked_ioctl:    ft1000_ChIoctl,
85     poll:     ft1000_ChPoll,
86     open:     ft1000_ChOpen,
87     release:  ft1000_ChRelease
88 };
89
90
91
92
93 //---------------------------------------------------------------------------
94 // Function:    exec_mknod
95 //
96 // Parameters:
97 //
98 // Returns:
99 //
100 // Description:
101 //
102 // Notes:
103 //
104 //---------------------------------------------------------------------------
105 static int exec_mknod (void *pdata)
106 {
107     PFT1000_INFO info;
108     char mjnum[4];
109     char minornum[4];
110     char temp[32];
111     int retcode;
112 //    int i;                                    //aelias [-] reason : unused variable
113     char *envp[] = { "HOME=/", "PATH=/usr/bin:/bin", NULL };
114     char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL};
115
116     info = pdata;
117     DEBUG("ft1000_chdev:exec_mknod is called with major number = %d\n", info->DeviceMajor);
118     sprintf(temp, "%s%s", "/dev/", info->DeviceName) ;
119     sprintf(mjnum, "%d", info->DeviceMajor);
120     sprintf(minornum, "%d", info->CardNumber);
121
122     //char *argv[]={"mknod","-m 666",temp,"c",mjnum,minornum,NULL};
123 //    char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL};
124
125     //for (i=0; i<7;i++)
126     //    DEBUG("argv[%d]=%s\n", i, argv[i]);
127
128
129     retcode = call_usermodehelper ("/bin/mknod", argv, envp, 1);
130     if (retcode) {
131         DEBUG("ft1000_chdev:exec_mknod failed to make the node: retcode = %d\n", retcode);
132     }
133
134
135
136     return retcode;
137
138 }
139
140 //---------------------------------------------------------------------------
141 // Function:    rm_mknod
142 //
143 // Description: This module removes the FT1000 device file
144 //
145 //---------------------------------------------------------------------------
146 static int rm_mknod (void *pdata)
147 {
148
149     PFT1000_INFO info;
150     //char *argv[4]={"rm", "-f", "/dev/FT1000", NULL};
151     int retcode;
152     char temp[32];
153     char *argv[]={"rm", "-f", temp, NULL};
154
155     info = (PFT1000_INFO)pdata;
156     DEBUG("ft1000_chdev:rm_mknod is called for device %s\n", info->DeviceName);
157     sprintf(temp, "%s%s", "/dev/", info->DeviceName) ;
158
159 //    char *argv[]={"rm", "-f", temp, NULL};
160
161     retcode = call_usermodehelper ("/bin/rm", argv, NULL, 1);
162     if (retcode) {
163         DEBUG("ft1000_chdev:rm_mknod failed to remove the node: retcode = %d\n", retcode);
164     }
165     else
166         DEBUG("ft1000_chdev:rm_mknod done!\n");
167
168
169     return retcode;
170
171 }
172 //---------------------------------------------------------------------------
173 // Function:    ft1000_get_buffer
174 //
175 // Parameters:
176 //
177 // Returns:
178 //
179 // Description:
180 //
181 // Notes:
182 //
183 //---------------------------------------------------------------------------
184 PDPRAM_BLK ft1000_get_buffer (struct list_head *bufflist)
185 {
186     unsigned long flags;
187     PDPRAM_BLK ptr;
188
189     spin_lock_irqsave(&free_buff_lock, flags);
190     // Check if buffer is available
191     if ( list_empty(bufflist) ) {
192         DEBUG("ft1000_get_buffer:  No more buffer - %d\n", numofmsgbuf);
193         ptr = NULL;
194     }
195     else {
196         numofmsgbuf--;
197         ptr = list_entry(bufflist->next, DPRAM_BLK, list);
198         list_del(&ptr->list);
199         //DEBUG("ft1000_get_buffer: number of free msg buffers = %d\n", numofmsgbuf);
200     }
201     spin_unlock_irqrestore(&free_buff_lock, flags);
202
203     return ptr;
204 }
205
206
207
208
209 //---------------------------------------------------------------------------
210 // Function:    ft1000_free_buffer
211 //
212 // Parameters:
213 //
214 // Returns:
215 //
216 // Description:
217 //
218 // Notes:
219 //
220 //---------------------------------------------------------------------------
221 void ft1000_free_buffer (PDPRAM_BLK pdpram_blk, struct list_head *plist)
222 {
223     unsigned long flags;
224
225     spin_lock_irqsave(&free_buff_lock, flags);
226     // Put memory back to list
227     list_add_tail(&pdpram_blk->list, plist);
228     numofmsgbuf++;
229     //DEBUG("ft1000_free_buffer: number of free msg buffers = %d\n", numofmsgbuf);
230     spin_unlock_irqrestore(&free_buff_lock, flags);
231 }
232
233 //---------------------------------------------------------------------------
234 // Function:    ft1000_CreateDevice
235 //
236 // Parameters:  dev - pointer to adapter object
237 //
238 // Returns:     0 if successful
239 //
240 // Description: Creates a private char device.
241 //
242 // Notes:       Only called by init_module().
243 //
244 //---------------------------------------------------------------------------
245 int ft1000_CreateDevice(struct ft1000_device *dev)
246 {
247     PFT1000_INFO info = netdev_priv(dev->net);
248     int result;
249     int i;
250     pid_t pid;
251
252     // make a new device name
253     sprintf(info->DeviceName, "%s%d", "FT100", info->CardNumber);
254
255     // Delete any existing FT1000 node
256     pid = kernel_thread (rm_mknod,(void *)info, 0);
257     msleep(1000);
258
259     DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt);
260     DEBUG("DeviceCreated = %x\n", info->DeviceCreated);
261
262     //save the device info to global array
263     pdevobj[info->CardNumber] = dev;
264
265     DEBUG("ft1000_CreateDevice: ******SAVED pdevobj[%d]=%x\n", info->CardNumber, (unsigned int)pdevobj[info->CardNumber]);      //aelias [+] reason:up
266
267     if (info->DeviceCreated)
268     {
269         DEBUG("ft1000_CreateDevice: \"%s\" already registered\n", info->DeviceName);
270         return -EIO;
271     }
272
273
274     // register the device
275     DEBUG("ft1000_CreateDevice: \"%s\" device registration\n", info->DeviceName);
276     info->DeviceMajor = 0;
277
278     result = register_chrdev(info->DeviceMajor, info->DeviceName, &ft1000fops);
279     if (result < 0)
280     {
281         DEBUG("ft1000_CreateDevice: unable to get major %d\n", info->DeviceMajor);
282         return result;
283     }
284
285     DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName);
286
287     // save a dynamic device major number
288     if (info->DeviceMajor == 0)
289     {
290         info->DeviceMajor = result;
291         DEBUG("ft1000_PcdCreateDevice: device major = %d\n", info->DeviceMajor);
292     }
293
294     // Create a thread to call user mode app to mknod
295     pid = kernel_thread (exec_mknod, (void *)info, 0);
296
297     // initialize application information
298     info->appcnt = 0;
299
300 //    if (ft1000_flarion_cnt == 0) {
301 //
302 //        DEBUG("Initialize free_buff_lock and freercvpool\n");
303 //        spin_lock_init(&free_buff_lock);
304 //
305 //        // initialize a list of buffers to be use for queuing up receive command data
306 //        INIT_LIST_HEAD (&freercvpool);
307 //
308 //        // create list of free buffers
309 //        for (i=0; i<NUM_OF_FREE_BUFFERS; i++) {
310 //            // Get memory for DPRAM_DATA link list
311 //            pdpram_blk = kmalloc ( sizeof(DPRAM_BLK), GFP_KERNEL );
312 //            // Get a block of memory to store command data
313 //            pdpram_blk->pbuffer = kmalloc ( MAX_CMD_SQSIZE, GFP_KERNEL );
314 //            // link provisioning data
315 //            list_add_tail (&pdpram_blk->list, &freercvpool);
316 //        }
317 //        numofmsgbuf = NUM_OF_FREE_BUFFERS;
318 //    }
319
320
321     // initialize application information
322     info->appcnt = 0;
323     for (i=0; i<MAX_NUM_APP; i++) {
324         info->app_info[i].nTxMsg = 0;
325         info->app_info[i].nRxMsg = 0;
326         info->app_info[i].nTxMsgReject = 0;
327         info->app_info[i].nRxMsgMiss = 0;
328         info->app_info[i].fileobject = 0;
329         info->app_info[i].app_id = i+1;
330         info->app_info[i].DspBCMsgFlag = 0;
331         info->app_info[i].NumOfMsg = 0;
332         init_waitqueue_head(&info->app_info[i].wait_dpram_msg);
333         INIT_LIST_HEAD (&info->app_info[i].app_sqlist);
334     }
335
336
337
338
339 //    ft1000Handle[info->CardNumber] = devfs_register(NULL, info->DeviceName, DEVFS_FL_AUTO_DEVNUM, 0, 0,
340 //                                  S_IFCHR | S_IRUGO | S_IWUGO, &ft1000fops, NULL);
341
342
343     info->DeviceCreated = TRUE;
344     ft1000_flarion_cnt++;
345
346     return result;
347 }
348
349 //---------------------------------------------------------------------------
350 // Function:    ft1000_DestroyDeviceDEBUG
351 //
352 // Parameters:  dev - pointer to adapter object
353 //
354 // Description: Destroys a private char device.
355 //
356 // Notes:       Only called by cleanup_module().
357 //
358 //---------------------------------------------------------------------------
359 void ft1000_DestroyDevice(struct net_device *dev)
360 {
361     PFT1000_INFO info = netdev_priv(dev);
362     int result = 0;
363     pid_t pid;
364                 int i;
365     PDPRAM_BLK pdpram_blk;
366     DPRAM_BLK *ptr;
367
368     DEBUG("ft1000_chdev:ft1000_DestroyDevice called\n");
369
370
371
372     if (info->DeviceCreated)
373         {
374         ft1000_flarion_cnt--;
375                 unregister_chrdev(info->DeviceMajor, info->DeviceName);
376                 DEBUG("ft1000_DestroyDevice: unregistered device \"%s\", result = %d\n",
377                                            info->DeviceName, result);
378
379        pid = kernel_thread (rm_mknod, (void *)info, 0);
380
381         // Make sure we free any memory reserve for slow Queue
382         for (i=0; i<MAX_NUM_APP; i++) {
383             while (list_empty(&info->app_info[i].app_sqlist) == 0) {
384                 pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, DPRAM_BLK, list);
385                 list_del(&pdpram_blk->list);
386                 ft1000_free_buffer(pdpram_blk, &freercvpool);
387
388             }
389             wake_up_interruptible(&info->app_info[i].wait_dpram_msg);
390         }
391
392         // Remove buffer allocated for receive command data
393         if (ft1000_flarion_cnt == 0) {
394             while (list_empty(&freercvpool) == 0) {
395                 ptr = list_entry(freercvpool.next, DPRAM_BLK, list);
396                 list_del(&ptr->list);
397                 kfree(ptr->pbuffer);
398                 kfree(ptr);
399             }
400         }
401
402 //        devfs_unregister(ft1000Handle[info->CardNumber]);
403
404                 info->DeviceCreated = FALSE;
405
406                 pdevobj[info->CardNumber] = NULL;
407         }
408
409
410 }
411
412 //---------------------------------------------------------------------------
413 // Function:    ft1000_ChOpen
414 //
415 // Parameters:
416 //
417 // Description:
418 //
419 // Notes:
420 //
421 //---------------------------------------------------------------------------
422 static int ft1000_ChOpen (struct inode *Inode, struct file *File)
423 {
424     PFT1000_INFO info;
425     int i,num;
426
427     DEBUG("ft1000_ChOpen called\n");
428     num = (MINOR(Inode->i_rdev) & 0xf);
429     DEBUG("ft1000_ChOpen: minor number=%d\n", num);
430
431     for (i=0; i<5; i++)
432         DEBUG("pdevobj[%d]=%x\n", i, (unsigned int)pdevobj[i]); //aelias [+] reason: down
433
434     if ( pdevobj[num] != NULL )
435         //info = (PFT1000_INFO)(pdevobj[num]->net->priv);
436         info = (FT1000_INFO *) netdev_priv (pdevobj[num]->net);
437     else
438     {
439         DEBUG("ft1000_ChOpen: can not find device object %d\n", num);
440         return -1;
441     }
442
443     DEBUG("f_owner = 0x%8x number of application = %d\n", (u32)(&File->f_owner), info->appcnt );
444
445     // Check if maximum number of application exceeded
446     if (info->appcnt > MAX_NUM_APP) {
447         DEBUG("Maximum number of application exceeded\n");
448         return -EACCES;
449     }
450
451     // Search for available application info block
452     for (i=0; i<MAX_NUM_APP; i++) {
453         if ( (info->app_info[i].fileobject == 0) ) {
454             break;
455         }
456     }
457
458     // Fail due to lack of application info block
459     if (i == MAX_NUM_APP) {
460         DEBUG("Could not find an application info block\n");
461         return -EACCES;
462     }
463
464     info->appcnt++;
465     info->app_info[i].fileobject = (u32)(&File->f_owner);
466     info->app_info[i].nTxMsg = 0;
467     info->app_info[i].nRxMsg = 0;
468     info->app_info[i].nTxMsgReject = 0;
469     info->app_info[i].nRxMsgMiss = 0;
470
471     File->private_data = pdevobj[num]->net;
472
473     return 0;
474 }
475
476
477 //---------------------------------------------------------------------------
478 // Function:    ft1000_ChPoll
479 //
480 // Parameters:
481 //
482 // Description:
483 //
484 // Notes:
485 //
486 //---------------------------------------------------------------------------
487
488 static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait)
489 {
490     struct net_device *dev = file->private_data;
491     PFT1000_INFO info;
492     int i;
493
494     //DEBUG("ft1000_ChPoll called\n");
495     if (ft1000_flarion_cnt == 0) {
496         DEBUG("FT1000:ft1000_ChPoll called when ft1000_flarion_cnt is zero\n");
497         return (-EBADF);
498     }
499
500         info = (FT1000_INFO *) netdev_priv (dev);
501
502     // Search for matching file object
503     for (i=0; i<MAX_NUM_APP; i++) {
504         if ( info->app_info[i].fileobject == (u32)(&file->f_owner) ) {
505             //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
506             break;
507         }
508     }
509
510     // Could not find application info block
511     if (i == MAX_NUM_APP) {
512         DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n");
513         return ( -EACCES );
514     }
515
516     if (list_empty(&info->app_info[i].app_sqlist) == 0) {
517         DEBUG("FT1000:ft1000_ChPoll:Message detected in slow queue\n");
518         return(POLLIN | POLLRDNORM | POLLPRI);
519     }
520
521     poll_wait (file, &info->app_info[i].wait_dpram_msg, wait);
522     //DEBUG("FT1000:ft1000_ChPoll:Polling for data from DSP\n");
523
524     return (0);
525 }
526
527 //---------------------------------------------------------------------------
528 // Function:    ft1000_ChIoctl
529 //
530 // Parameters:
531 //
532 // Description:
533 //
534 // Notes:
535 //
536 //---------------------------------------------------------------------------
537 static int ft1000_ChIoctl (struct file *File, unsigned int Command,
538                            unsigned long Argument)
539 {
540     struct net_device *dev;
541     PFT1000_INFO info;
542     struct ft1000_device *ft1000dev;
543     int result=0;
544     int cmd;
545     int i;
546     u16 tempword;
547     unsigned long flags;
548     struct timeval tv;
549     IOCTL_GET_VER get_ver_data;
550     IOCTL_GET_DSP_STAT get_stat_data;
551     u8 ConnectionMsg[] = {0x00,0x44,0x10,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x93,0x64,
552                           0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a,
553                           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
554                           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
555                           0x00,0x00,0x02,0x37,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x7f,0x00,
556                           0x00,0x01,0x00,0x00};
557
558     unsigned short ledStat=0;
559     unsigned short conStat=0;
560
561     //DEBUG("ft1000_ChIoctl called\n");
562
563     if (ft1000_flarion_cnt == 0) {
564         DEBUG("FT1000:ft1000_ChIoctl called when ft1000_flarion_cnt is zero\n");
565         return (-EBADF);
566     }
567
568     //DEBUG("FT1000:ft1000_ChIoctl:Command = 0x%x Argument = 0x%8x\n", Command, (u32)Argument);
569
570     dev = File->private_data;
571         info = (FT1000_INFO *) netdev_priv (dev);
572     ft1000dev = info->pFt1000Dev;
573     cmd = _IOC_NR(Command);
574     //DEBUG("FT1000:ft1000_ChIoctl:cmd = 0x%x\n", cmd);
575
576     // process the command
577     switch (cmd) {
578     case IOCTL_REGISTER_CMD:
579             DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_REGISTER called\n");
580             result = get_user(tempword, (unsigned short *)Argument);
581             if (result) {
582                 DEBUG("result = %d failed to get_user\n", result);
583                 break;
584             }
585             if (tempword == DSPBCMSGID) {
586                 // Search for matching file object
587                 for (i=0; i<MAX_NUM_APP; i++) {
588                     if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
589                         info->app_info[i].DspBCMsgFlag = 1;
590                         DEBUG("FT1000:ft1000_ChIoctl:Registered for broadcast messages\n");
591                         break;
592                     }
593                 }
594             }
595             break;
596
597     case IOCTL_GET_VER_CMD:
598         DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_VER called\n");
599
600         get_ver_data.drv_ver = FT1000_DRV_VER;
601
602         if (copy_to_user((PIOCTL_GET_VER)Argument, &get_ver_data, sizeof(get_ver_data)) ) {
603             DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
604             result = -EFAULT;
605             break;
606         }
607
608         DEBUG("FT1000:ft1000_ChIoctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver);
609
610         break;
611     case IOCTL_CONNECT:
612         // Connect Message
613         DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_CONNECT\n");
614         ConnectionMsg[79] = 0xfc;
615                            CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
616
617         break;
618     case IOCTL_DISCONNECT:
619         // Disconnect Message
620         DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_DISCONNECT\n");
621         ConnectionMsg[79] = 0xfd;
622                            CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
623         break;
624     case IOCTL_GET_DSP_STAT_CMD:
625         //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DSP_STAT called\n");
626
627         memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ);
628         memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ);
629         memcpy(get_stat_data.Sku, info->Sku, SKUSZ);
630         memcpy(get_stat_data.eui64, info->eui64, EUISZ);
631
632             if (info->ProgConStat != 0xFF) {
633                 ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (PUCHAR)&ledStat, FT1000_MAG_DSP_LED_INDX);
634                 get_stat_data.LedStat = ntohs(ledStat);
635                 DEBUG("FT1000:ft1000_ChIoctl: LedStat = 0x%x\n", get_stat_data.LedStat);
636                 ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (PUCHAR)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
637                 get_stat_data.ConStat = ntohs(conStat);
638                 DEBUG("FT1000:ft1000_ChIoctl: ConStat = 0x%x\n", get_stat_data.ConStat);
639             }
640             else {
641                 get_stat_data.ConStat = 0x0f;
642             }
643
644
645         get_stat_data.nTxPkts = info->stats.tx_packets;
646         get_stat_data.nRxPkts = info->stats.rx_packets;
647         get_stat_data.nTxBytes = info->stats.tx_bytes;
648         get_stat_data.nRxBytes = info->stats.rx_bytes;
649         do_gettimeofday ( &tv );
650         get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm);
651         DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm);
652         if (copy_to_user((PIOCTL_GET_DSP_STAT)Argument, &get_stat_data, sizeof(get_stat_data)) ) {
653             DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
654             result = -EFAULT;
655             break;
656         }
657         DEBUG("ft1000_chioctl: GET_DSP_STAT succeed\n");
658         break;
659     case IOCTL_SET_DPRAM_CMD:
660         {
661             IOCTL_DPRAM_BLK dpram_data;
662             //IOCTL_DPRAM_COMMAND dpram_command;
663             USHORT qtype;
664             USHORT msgsz;
665             PPSEUDO_HDR ppseudo_hdr;
666             PUSHORT pmsg;
667             USHORT total_len;
668             USHORT app_index;
669             u16 status;
670
671             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_SET_DPRAM called\n");
672
673
674             if (ft1000_flarion_cnt == 0) {
675                 return (-EBADF);
676             }
677
678             if (info->DrvMsgPend) {
679                 return (-ENOTTY);
680             }
681
682             if ( (info->DspAsicReset) || (info->fProvComplete == 0) ) {
683                 return (-EACCES);
684             }
685
686             info->fAppMsgPend = 1;
687
688             if (info->CardReady) {
689
690                //DEBUG("FT1000:ft1000_ChIoctl: try to SET_DPRAM \n");
691
692                 // Get the length field to see how many bytes to copy
693                 result = get_user(msgsz, (unsigned short *)Argument);
694                 msgsz = ntohs (msgsz);
695                 //DEBUG("FT1000:ft1000_ChIoctl: length of message = %d\n", msgsz);
696
697                 if (msgsz > MAX_CMD_SQSIZE) {
698                     DEBUG("FT1000:ft1000_ChIoctl: bad message length = %d\n", msgsz);
699                     result = -EINVAL;
700                     break;
701                 }
702
703                 //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) {
704                 if ( copy_from_user(&dpram_data, (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) {
705                     DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
706                     result = -EFAULT;
707                 }
708                 else {
709 #if 0
710                     // whc - for debugging only
711                     ptr = (char *)&dpram_data;
712                     for (i=0; i<msgsz; i++) {
713                         DEBUG(1,"FT1000:ft1000_ChIoctl: data %d = 0x%x\n", i, *ptr++);
714                     }
715 #endif
716                     // Check if this message came from a registered application
717                     for (i=0; i<MAX_NUM_APP; i++) {
718                         if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
719                             break;
720                         }
721                     }
722                     if (i==MAX_NUM_APP) {
723                         DEBUG("FT1000:No matching application fileobject\n");
724                         result = -EINVAL;
725                         break;
726                     }
727                     app_index = i;
728
729                     // Check message qtype type which is the lower byte within qos_class
730                     //qtype = ntohs(dpram_command.dpram_blk.pseudohdr.qos_class) & 0xff;
731                     qtype = ntohs(dpram_data.pseudohdr.qos_class) & 0xff;
732                     //DEBUG("FT1000_ft1000_ChIoctl: qtype = %d\n", qtype);
733                     if (qtype) {
734                     }
735                     else {
736                         // Put message into Slow Queue
737                         // Only put a message into the DPRAM if msg doorbell is available
738                         status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
739                         //DEBUG("FT1000_ft1000_ChIoctl: READ REGISTER tempword=%x\n", tempword);
740                         if (tempword & FT1000_DB_DPRAM_TX) {
741                             // Suspend for 2ms and try again due to DSP doorbell busy
742                             mdelay(2);
743                             status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
744                             if (tempword & FT1000_DB_DPRAM_TX) {
745                                 // Suspend for 1ms and try again due to DSP doorbell busy
746                                 mdelay(1);
747                                 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
748                                 if (tempword & FT1000_DB_DPRAM_TX) {
749                                     status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
750                                     if (tempword & FT1000_DB_DPRAM_TX) {
751                                         // Suspend for 3ms and try again due to DSP doorbell busy
752                                         mdelay(3);
753                                         status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
754                                         if (tempword & FT1000_DB_DPRAM_TX) {
755                                             DEBUG("FT1000:ft1000_ChIoctl:Doorbell not available\n");
756                                             result = -ENOTTY;
757                                             break;
758                                         }
759                                     }
760                                 }
761                             }
762                         }
763
764                         //DEBUG("FT1000_ft1000_ChIoctl: finished reading register\n");
765
766                         // Make sure we are within the limits of the slow queue memory limitation
767                         if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) {
768                             // Need to put sequence number plus new checksum for message
769                             //pmsg = (PUSHORT)&dpram_command.dpram_blk.pseudohdr;
770                             pmsg = (PUSHORT)&dpram_data.pseudohdr;
771                             ppseudo_hdr = (PPSEUDO_HDR)pmsg;
772                             total_len = msgsz+2;
773                             if (total_len & 0x1) {
774                                 total_len++;
775                             }
776
777                             // Insert slow queue sequence number
778                             ppseudo_hdr->seq_num = info->squeseqnum++;
779                             ppseudo_hdr->portsrc = info->app_info[app_index].app_id;
780                             // Calculate new checksum
781                             ppseudo_hdr->checksum = *pmsg++;
782                             //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum);
783                             for (i=1; i<7; i++) {
784                                 ppseudo_hdr->checksum ^= *pmsg++;
785                                 //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum);
786                             }
787                             pmsg++;
788                             ppseudo_hdr = (PPSEUDO_HDR)pmsg;
789 #if 0
790                             ptr = (char *)&dpram_data;
791                             DEBUG("FT1000:ft1000_ChIoctl: Command Send\n");
792                             for (i=0; i<total_len; i++) {
793                                 DEBUG("FT1000:ft1000_ChIoctl: data %d = 0x%x\n", i, *ptr++);
794                             }
795 #endif
796                             //dpram_command.extra = 0;
797
798                             //CardSendCommand(ft1000dev,(unsigned char*)&dpram_command,total_len+2);
799                             CardSendCommand(ft1000dev,(unsigned short*)&dpram_data,total_len+2);
800
801
802                             info->app_info[app_index].nTxMsg++;
803                             break;
804                         }
805                         else {
806                             result = -EINVAL;
807                             break;
808                         }
809                     }
810                 }
811             }
812             else {
813                 DEBUG("FT1000:ft1000_ChIoctl: Card not ready take messages\n");
814                 result = -EACCES;
815             }
816
817         }
818         break;
819     case IOCTL_GET_DPRAM_CMD:
820         {
821             PDPRAM_BLK pdpram_blk;
822             PIOCTL_DPRAM_BLK pioctl_dpram;
823             int msglen;
824
825             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM called\n");
826
827             if (ft1000_flarion_cnt == 0) {
828                 return (-EBADF);
829             }
830
831             // Search for matching file object
832             for (i=0; i<MAX_NUM_APP; i++) {
833                 if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
834                     //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
835                     break;
836                 }
837             }
838
839             // Could not find application info block
840             if (i == MAX_NUM_APP) {
841                 DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n");
842                 result = -EBADF;
843                 break;
844             }
845
846             result = 0;
847             pioctl_dpram = (PIOCTL_DPRAM_BLK)Argument;
848             if (list_empty(&info->app_info[i].app_sqlist) == 0) {
849                 //DEBUG("FT1000:ft1000_ChIoctl:Message detected in slow queue\n");
850                 spin_lock_irqsave(&free_buff_lock, flags);
851                 pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, DPRAM_BLK, list);
852                 list_del(&pdpram_blk->list);
853                 info->app_info[i].NumOfMsg--;
854                 //DEBUG("FT1000:ft1000_ChIoctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg);
855                 spin_unlock_irqrestore(&free_buff_lock, flags);
856                 msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ;
857                 pioctl_dpram->total_len = htons(msglen);
858                 //DEBUG("FT1000:ft1000_ChIoctl:msg length = %x\n", msglen);
859                 if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen))
860                                 {
861                                         DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
862                         result = -EFAULT;
863                         break;
864                                 }
865
866                 ft1000_free_buffer(pdpram_blk, &freercvpool);
867                 result = msglen;
868             }
869             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM no message\n");
870         }
871         break;
872
873     default:
874         DEBUG("FT1000:ft1000_ChIoctl:unknown command: 0x%x\n", Command);
875         result = -ENOTTY;
876         break;
877     }
878     info->fAppMsgPend = 0;
879     return result;
880 }
881
882 //---------------------------------------------------------------------------
883 // Function:    ft1000_ChRelease
884 //
885 // Parameters:
886 //
887 // Description:
888 //
889 // Notes:
890 //
891 //---------------------------------------------------------------------------
892 static int ft1000_ChRelease (struct inode *Inode, struct file *File)
893 {
894     PFT1000_INFO info;
895     struct net_device *dev;
896     int i;
897     PDPRAM_BLK pdpram_blk;
898
899     DEBUG("ft1000_ChRelease called\n");
900
901     dev = File->private_data;
902         info = (FT1000_INFO *) netdev_priv (dev);
903
904     if (ft1000_flarion_cnt == 0) {
905         info->appcnt--;
906         return (-EBADF);
907     }
908
909     // Search for matching file object
910     for (i=0; i<MAX_NUM_APP; i++) {
911         if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
912             //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
913             break;
914         }
915     }
916
917     if (i==MAX_NUM_APP)
918             return 0;
919
920     while (list_empty(&info->app_info[i].app_sqlist) == 0) {
921         DEBUG("Remove and free memory queue up on slow queue\n");
922         pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, DPRAM_BLK, list);
923         list_del(&pdpram_blk->list);
924         ft1000_free_buffer(pdpram_blk, &freercvpool);
925     }
926
927     // initialize application information
928     info->appcnt--;
929     DEBUG("ft1000_chdev:%s:appcnt = %d\n", __FUNCTION__, info->appcnt);
930     info->app_info[i].fileobject = 0;
931
932     return 0;
933 }
934