2 *---------------------------------------------------------------------------
3 * FT1000 driver for Flarion Flash OFDM NIC Device
5 * Copyright (C) 2006 Flarion Technologies, All rights reserved.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option) any
10 * later version. This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details. You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place -
16 * Suite 330, Boston, MA 02111-1307, USA.
17 *---------------------------------------------------------------------------
19 * File: ft1000_chdev.c
21 * Description: Custom character device dispatch routines.
24 * 8/29/02 Whc Ported to Linux.
25 * 6/05/06 Whc Porting to Linux 2.6.9
27 *---------------------------------------------------------------------------
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/sched.h>
35 #include <linux/errno.h>
36 #include <linux/poll.h>
37 #include <linux/netdevice.h>
38 #include <linux/delay.h>
40 #include <linux/ioctl.h>
41 #include <linux/debugfs.h>
42 #include "ft1000_usb.h"
44 static int ft1000_flarion_cnt;
46 static int ft1000_open(struct inode *inode, struct file *file);
47 static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait);
48 static long ft1000_ioctl(struct file *file, unsigned int command,
49 unsigned long argument);
50 static int ft1000_release(struct inode *inode, struct file *file);
52 /* List to free receive command buffer pool */
53 struct list_head freercvpool;
55 /* lock to arbitrate free buffer list for receive command data */
56 spinlock_t free_buff_lock;
61 * Table of entry-point routines for char device
63 static const struct file_operations ft1000fops = {
64 .unlocked_ioctl = ft1000_ioctl,
65 .poll = ft1000_poll_dev,
67 .release = ft1000_release,
72 ---------------------------------------------------------------------------
73 * Function: ft1000_get_buffer
83 *---------------------------------------------------------------------------
85 struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist)
88 struct dpram_blk *ptr;
90 spin_lock_irqsave(&free_buff_lock, flags);
91 /* Check if buffer is available */
92 if (list_empty(bufflist)) {
93 pr_debug("No more buffer - %d\n", numofmsgbuf);
97 ptr = list_entry(bufflist->next, struct dpram_blk, list);
99 /* pr_debug("number of free msg buffers = %d\n", numofmsgbuf); */
101 spin_unlock_irqrestore(&free_buff_lock, flags);
110 *---------------------------------------------------------------------------
111 * Function: ft1000_free_buffer
121 *---------------------------------------------------------------------------
123 void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist)
127 spin_lock_irqsave(&free_buff_lock, flags);
128 /* Put memory back to list */
129 list_add_tail(&pdpram_blk->list, plist);
131 /*pr_debug("number of free msg buffers = %d\n", numofmsgbuf); */
132 spin_unlock_irqrestore(&free_buff_lock, flags);
136 *---------------------------------------------------------------------------
137 * Function: ft1000_CreateDevice
139 * Parameters: dev - pointer to adapter object
141 * Returns: 0 if successful
143 * Description: Creates a private char device.
145 * Notes: Only called by init_module().
147 *---------------------------------------------------------------------------
149 int ft1000_create_dev(struct ft1000_usb *dev)
153 struct dentry *dir, *file;
154 struct ft1000_debug_dirs *tmp;
156 /* make a new device name */
157 sprintf(dev->DeviceName, "%s%d", "FT1000_", dev->CardNumber);
159 pr_debug("number of instance = %d\n", ft1000_flarion_cnt);
160 pr_debug("DeviceCreated = %x\n", dev->DeviceCreated);
162 if (dev->DeviceCreated) {
163 pr_debug("\"%s\" already registered\n", dev->DeviceName);
168 /* register the device */
169 pr_debug("\"%s\" debugfs device registration\n", dev->DeviceName);
171 tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL);
177 dir = debugfs_create_dir(dev->DeviceName, NULL);
179 result = PTR_ERR(dir);
183 file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir,
186 result = PTR_ERR(file);
187 goto debug_file_fail;
192 tmp->int_number = dev->CardNumber;
193 list_add(&(tmp->list), &(dev->nodes.list));
195 pr_debug("registered debugfs directory \"%s\"\n", dev->DeviceName);
197 /* initialize application information */
199 for (i = 0; i < MAX_NUM_APP; i++) {
200 dev->app_info[i].nTxMsg = 0;
201 dev->app_info[i].nRxMsg = 0;
202 dev->app_info[i].nTxMsgReject = 0;
203 dev->app_info[i].nRxMsgMiss = 0;
204 dev->app_info[i].fileobject = NULL;
205 dev->app_info[i].app_id = i+1;
206 dev->app_info[i].DspBCMsgFlag = 0;
207 dev->app_info[i].NumOfMsg = 0;
208 init_waitqueue_head(&dev->app_info[i].wait_dpram_msg);
209 INIT_LIST_HEAD(&dev->app_info[i].app_sqlist);
212 dev->DeviceCreated = TRUE;
213 ft1000_flarion_cnt++;
226 *---------------------------------------------------------------------------
227 * Function: ft1000_DestroyDeviceDEBUG
229 * Parameters: dev - pointer to adapter object
231 * Description: Destroys a private char device.
233 * Notes: Only called by cleanup_module().
235 *---------------------------------------------------------------------------
237 void ft1000_destroy_dev(struct net_device *netdev)
239 struct ft1000_info *info = netdev_priv(netdev);
240 struct ft1000_usb *dev = info->priv;
242 struct dpram_blk *pdpram_blk;
243 struct dpram_blk *ptr;
244 struct list_head *pos, *q;
245 struct ft1000_debug_dirs *dir;
247 if (dev->DeviceCreated) {
248 ft1000_flarion_cnt--;
249 list_for_each_safe(pos, q, &dev->nodes.list) {
250 dir = list_entry(pos, struct ft1000_debug_dirs, list);
251 if (dir->int_number == dev->CardNumber) {
252 debugfs_remove(dir->file);
253 debugfs_remove(dir->dent);
258 pr_debug("unregistered device \"%s\"\n", dev->DeviceName);
260 /* Make sure we free any memory reserve for slow Queue */
261 for (i = 0; i < MAX_NUM_APP; i++) {
262 while (list_empty(&dev->app_info[i].app_sqlist) == 0) {
263 pdpram_blk = list_entry(dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
264 list_del(&pdpram_blk->list);
265 ft1000_free_buffer(pdpram_blk, &freercvpool);
268 wake_up_interruptible(&dev->app_info[i].wait_dpram_msg);
271 /* Remove buffer allocated for receive command data */
272 if (ft1000_flarion_cnt == 0) {
273 while (list_empty(&freercvpool) == 0) {
274 ptr = list_entry(freercvpool.next, struct dpram_blk, list);
275 list_del(&ptr->list);
280 dev->DeviceCreated = FALSE;
287 *---------------------------------------------------------------------------
288 * Function: ft1000_open
296 *---------------------------------------------------------------------------
298 static int ft1000_open(struct inode *inode, struct file *file)
300 struct ft1000_info *info;
301 struct ft1000_usb *dev = (struct ft1000_usb *)inode->i_private;
304 num = (MINOR(inode->i_rdev) & 0xf);
305 pr_debug("minor number=%d\n", num);
307 info = file->private_data = netdev_priv(dev->net);
309 pr_debug("f_owner = %p number of application = %d\n",
310 &file->f_owner, dev->appcnt);
312 /* Check if maximum number of application exceeded */
313 if (dev->appcnt > MAX_NUM_APP) {
314 pr_debug("Maximum number of application exceeded\n");
318 /* Search for available application info block */
319 for (i = 0; i < MAX_NUM_APP; i++) {
320 if ((dev->app_info[i].fileobject == NULL)) {
325 /* Fail due to lack of application info block */
326 if (i == MAX_NUM_APP) {
327 pr_debug("Could not find an application info block\n");
332 dev->app_info[i].fileobject = &file->f_owner;
333 dev->app_info[i].nTxMsg = 0;
334 dev->app_info[i].nRxMsg = 0;
335 dev->app_info[i].nTxMsgReject = 0;
336 dev->app_info[i].nRxMsgMiss = 0;
338 nonseekable_open(inode, file);
344 *---------------------------------------------------------------------------
345 * Function: ft1000_poll_dev
353 *---------------------------------------------------------------------------
356 static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait)
358 struct net_device *netdev = file->private_data;
359 struct ft1000_info *info = netdev_priv(netdev);
360 struct ft1000_usb *dev = info->priv;
363 if (ft1000_flarion_cnt == 0) {
364 pr_debug("called with ft1000_flarion_cnt value zero\n");
368 /* Search for matching file object */
369 for (i = 0; i < MAX_NUM_APP; i++) {
370 if (dev->app_info[i].fileobject == &file->f_owner) {
371 /* pr_debug("Message is for AppId = %d\n", dev->app_info[i].app_id); */
376 /* Could not find application info block */
377 if (i == MAX_NUM_APP) {
378 pr_debug("Could not find application info block\n");
382 if (list_empty(&dev->app_info[i].app_sqlist) == 0) {
383 pr_debug("Message detected in slow queue\n");
384 return(POLLIN | POLLRDNORM | POLLPRI);
387 poll_wait(file, &dev->app_info[i].wait_dpram_msg, wait);
388 /* pr_debug("Polling for data from DSP\n"); */
394 *---------------------------------------------------------------------------
395 * Function: ft1000_ioctl
403 *---------------------------------------------------------------------------
405 static long ft1000_ioctl(struct file *file, unsigned int command,
406 unsigned long argument)
408 void __user *argp = (void __user *)argument;
409 struct ft1000_info *info;
410 struct ft1000_usb *ft1000dev;
417 struct IOCTL_GET_VER get_ver_data;
418 struct IOCTL_GET_DSP_STAT get_stat_data;
419 u8 ConnectionMsg[] = {0x00, 0x44, 0x10, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x93, 0x64,
420 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0a,
421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
423 0x00, 0x00, 0x02, 0x37, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, 0x00,
424 0x00, 0x01, 0x00, 0x00};
426 unsigned short ledStat = 0;
427 unsigned short conStat = 0;
429 if (ft1000_flarion_cnt == 0) {
430 pr_debug("called with ft1000_flarion_cnt of zero\n");
434 /* pr_debug("command = 0x%x argument = 0x%8x\n", command, (u32)argument); */
436 info = file->private_data;
437 ft1000dev = info->priv;
438 cmd = _IOC_NR(command);
439 /* pr_debug("cmd = 0x%x\n", cmd); */
441 /* process the command */
443 case IOCTL_REGISTER_CMD:
444 pr_debug("IOCTL_FT1000_REGISTER called\n");
445 result = get_user(tempword, (__u16 __user *)argp);
447 pr_debug("result = %d failed to get_user\n", result);
450 if (tempword == DSPBCMSGID) {
451 /* Search for matching file object */
452 for (i = 0; i < MAX_NUM_APP; i++) {
453 if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
454 ft1000dev->app_info[i].DspBCMsgFlag = 1;
455 pr_debug("Registered for broadcast messages\n");
462 case IOCTL_GET_VER_CMD:
463 pr_debug("IOCTL_FT1000_GET_VER called\n");
465 get_ver_data.drv_ver = FT1000_DRV_VER;
467 if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data))) {
468 pr_debug("copy fault occurred\n");
473 pr_debug("driver version = 0x%x\n",
474 (unsigned int)get_ver_data.drv_ver);
478 /* Connect Message */
479 pr_debug("IOCTL_FT1000_CONNECT\n");
480 ConnectionMsg[79] = 0xfc;
481 result = card_send_command(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
484 case IOCTL_DISCONNECT:
485 /* Disconnect Message */
486 pr_debug("IOCTL_FT1000_DISCONNECT\n");
487 ConnectionMsg[79] = 0xfd;
488 result = card_send_command(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
490 case IOCTL_GET_DSP_STAT_CMD:
491 /* pr_debug("IOCTL_FT1000_GET_DSP_STAT\n"); */
492 memset(&get_stat_data, 0, sizeof(get_stat_data));
493 memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ);
494 memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ);
495 memcpy(get_stat_data.Sku, info->Sku, SKUSZ);
496 memcpy(get_stat_data.eui64, info->eui64, EUISZ);
498 if (info->ProgConStat != 0xFF) {
499 ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
500 get_stat_data.LedStat = ntohs(ledStat);
501 pr_debug("LedStat = 0x%x\n", get_stat_data.LedStat);
502 ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
503 get_stat_data.ConStat = ntohs(conStat);
504 pr_debug("ConStat = 0x%x\n", get_stat_data.ConStat);
506 get_stat_data.ConStat = 0x0f;
510 get_stat_data.nTxPkts = info->stats.tx_packets;
511 get_stat_data.nRxPkts = info->stats.rx_packets;
512 get_stat_data.nTxBytes = info->stats.tx_bytes;
513 get_stat_data.nRxBytes = info->stats.rx_bytes;
514 do_gettimeofday(&tv);
515 get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm);
516 pr_debug("Connection Time = %d\n", (int)get_stat_data.ConTm);
517 if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data))) {
518 pr_debug("copy fault occurred\n");
522 pr_debug("GET_DSP_STAT succeed\n");
524 case IOCTL_SET_DPRAM_CMD:
526 struct IOCTL_DPRAM_BLK *dpram_data = NULL;
527 /* struct IOCTL_DPRAM_COMMAND dpram_command; */
530 struct pseudo_hdr *ppseudo_hdr;
536 /* pr_debug("IOCTL_FT1000_SET_DPRAM called\n");*/
539 if (ft1000_flarion_cnt == 0)
542 if (ft1000dev->DrvMsgPend)
545 if (ft1000dev->fProvComplete == 0)
548 ft1000dev->fAppMsgPend = 1;
550 if (info->CardReady) {
552 /* pr_debug("try to SET_DPRAM\n"); */
554 /* Get the length field to see how many bytes to copy */
555 result = get_user(msgsz, (__u16 __user *)argp);
558 msgsz = ntohs(msgsz);
559 /* pr_debug("length of message = %d\n", msgsz); */
561 if (msgsz > MAX_CMD_SQSIZE) {
562 pr_debug("bad message length = %d\n", msgsz);
568 dpram_data = kmalloc(msgsz + 2, GFP_KERNEL);
572 if (copy_from_user(dpram_data, argp, msgsz+2)) {
573 pr_debug("copy fault occurred\n");
576 /* Check if this message came from a registered application */
577 for (i = 0; i < MAX_NUM_APP; i++) {
578 if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
582 if (i == MAX_NUM_APP) {
583 pr_debug("No matching application fileobject\n");
590 /* Check message qtype type which is the lower byte within qos_class */
591 qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff;
592 /* pr_debug("qtype = %d\n", qtype); */
595 /* Put message into Slow Queue */
596 /* Only put a message into the DPRAM if msg doorbell is available */
597 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
598 /* pr_debug("READ REGISTER tempword=%x\n", tempword); */
599 if (tempword & FT1000_DB_DPRAM_TX) {
600 /* Suspend for 2ms and try again due to DSP doorbell busy */
602 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
603 if (tempword & FT1000_DB_DPRAM_TX) {
604 /* Suspend for 1ms and try again due to DSP doorbell busy */
606 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
607 if (tempword & FT1000_DB_DPRAM_TX) {
608 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
609 if (tempword & FT1000_DB_DPRAM_TX) {
610 /* Suspend for 3ms and try again due to DSP doorbell busy */
612 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
613 if (tempword & FT1000_DB_DPRAM_TX) {
614 pr_debug("Doorbell not available\n");
624 /*pr_debug("finished reading register\n"); */
626 /* Make sure we are within the limits of the slow queue memory limitation */
627 if ((msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ)) {
628 /* Need to put sequence number plus new checksum for message */
629 pmsg = (u16 *)&dpram_data->pseudohdr;
630 ppseudo_hdr = (struct pseudo_hdr *)pmsg;
632 if (total_len & 0x1) {
636 /* Insert slow queue sequence number */
637 ppseudo_hdr->seq_num = info->squeseqnum++;
638 ppseudo_hdr->portsrc = ft1000dev->app_info[app_index].app_id;
639 /* Calculate new checksum */
640 ppseudo_hdr->checksum = *pmsg++;
641 /* pr_debug("checksum = 0x%x\n", ppseudo_hdr->checksum); */
642 for (i = 1; i < 7; i++) {
643 ppseudo_hdr->checksum ^= *pmsg++;
644 /* pr_debug("checksum = 0x%x\n", ppseudo_hdr->checksum); */
647 ppseudo_hdr = (struct pseudo_hdr *)pmsg;
648 result = card_send_command(ft1000dev, (unsigned short *)dpram_data, total_len+2);
651 ft1000dev->app_info[app_index].nTxMsg++;
658 pr_debug("Card not ready take messages\n");
665 case IOCTL_GET_DPRAM_CMD:
667 struct dpram_blk *pdpram_blk;
668 struct IOCTL_DPRAM_BLK __user *pioctl_dpram;
671 /* pr_debug("IOCTL_FT1000_GET_DPRAM called\n"); */
673 if (ft1000_flarion_cnt == 0)
676 /* Search for matching file object */
677 for (i = 0; i < MAX_NUM_APP; i++) {
678 if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
679 /*pr_debug("Message is for AppId = %d\n", ft1000dev->app_info[i].app_id); */
684 /* Could not find application info block */
685 if (i == MAX_NUM_APP) {
686 pr_debug("Could not find application info block\n");
693 if (list_empty(&ft1000dev->app_info[i].app_sqlist) == 0) {
694 /* pr_debug("Message detected in slow queue\n"); */
695 spin_lock_irqsave(&free_buff_lock, flags);
696 pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
697 list_del(&pdpram_blk->list);
698 ft1000dev->app_info[i].NumOfMsg--;
699 /* pr_debug("NumOfMsg for app %d = %d\n", i, ft1000dev->app_info[i].NumOfMsg); */
700 spin_unlock_irqrestore(&free_buff_lock, flags);
701 msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ;
702 result = get_user(msglen, &pioctl_dpram->total_len);
705 msglen = htons(msglen);
706 /* pr_debug("msg length = %x\n", msglen); */
707 if (copy_to_user(&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen)) {
708 pr_debug("copy fault occurred\n");
713 ft1000_free_buffer(pdpram_blk, &freercvpool);
716 /* pr_debug("IOCTL_FT1000_GET_DPRAM no message\n"); */
721 pr_debug("unknown command: 0x%x\n", command);
725 ft1000dev->fAppMsgPend = 0;
730 *---------------------------------------------------------------------------
731 * Function: ft1000_release
739 *---------------------------------------------------------------------------
741 static int ft1000_release(struct inode *inode, struct file *file)
743 struct ft1000_info *info;
744 struct net_device *dev;
745 struct ft1000_usb *ft1000dev;
747 struct dpram_blk *pdpram_blk;
749 dev = file->private_data;
750 info = netdev_priv(dev);
751 ft1000dev = info->priv;
753 if (ft1000_flarion_cnt == 0) {
758 /* Search for matching file object */
759 for (i = 0; i < MAX_NUM_APP; i++) {
760 if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
761 /* pr_debug("Message is for AppId = %d\n", ft1000dev->app_info[i].app_id); */
766 if (i == MAX_NUM_APP)
769 while (list_empty(&ft1000dev->app_info[i].app_sqlist) == 0) {
770 pr_debug("Remove and free memory queue up on slow queue\n");
771 pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
772 list_del(&pdpram_blk->list);
773 ft1000_free_buffer(pdpram_blk, &freercvpool);
776 /* initialize application information */
778 pr_debug("appcnt = %d\n", ft1000dev->appcnt);
779 ft1000dev->app_info[i].fileobject = NULL;