u_char * b, /* buffer to fill */
int n) /* size to read */
{
- u_char * ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1);
+ net_local *lp = netdev_priv(dev);
+ u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1);
while(n-- > 0)
{
u_char * b, /* Buffer in memory */
int n) /* Length of buffer */
{
- u_char * ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1);
+ net_local *lp = netdev_priv(dev);
+ u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1);
int count = 0;
- ioaddr_t base = dev->base_addr;
+ kio_addr_t base = dev->base_addr;
/* As there seem to have no flag PSA_BUSY as in the ISA model, we are
* oblige to verify this address to know when the PSA is ready... */
- volatile u_char * verify = ((u_char *) dev->mem_start) + PSA_ADDR +
+ volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
(psaoff(0, psa_comp_number) << 1);
/* Authorize writting to PSA */
void wv_roam_init(struct net_device *dev)
{
- net_local *lp= (net_local *)dev->priv;
+ net_local *lp= netdev_priv(dev);
/* Do not remove this unless you have a good reason */
printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
void wv_roam_cleanup(struct net_device *dev)
{
wavepoint_history *ptr,*old_ptr;
- net_local *lp= (net_local *)dev->priv;
+ net_local *lp= netdev_priv(dev);
printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
/* Perform a handover to a new WavePoint */
void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
{
- ioaddr_t base = lp->dev->base_addr;
+ kio_addr_t base = lp->dev->base_addr;
mm_t m;
unsigned long flags;
unsigned short nwid=ntohs(beacon->nwid);
unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */
wavepoint_history *wavepoint=NULL; /* WavePoint table entry */
- net_local *lp=(net_local *)dev->priv; /* Device info */
+ net_local *lp = netdev_priv(dev); /* Device info */
#ifdef I_NEED_THIS_FEATURE
/* Some people don't need this, some other may need it */
int cmd,
int result)
{
- ioaddr_t base = dev->base_addr;
+ kio_addr_t base = dev->base_addr;
int status;
int wait_completed;
long spin;
OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
ret = TRUE;
-#ifdef DEBUG_CONFIG_ERROR
+#ifdef DEBUG_CONFIG_ERRORS
printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
#endif
return(ret);
char * buf,
int len)
{
- ioaddr_t base = dev->base_addr;
+ kio_addr_t base = dev->base_addr;
int ring_ptr = addr;
int chunk_len;
char * buf_ptr = buf;
static inline void
wv_82593_reconfig(struct net_device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local * lp = netdev_priv(dev);
dev_link_t * link = lp->link;
unsigned long flags;
static void
wv_mmc_show(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *)dev->priv;
+ kio_addr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
mmr_t m;
/* Basic check */
static void
wv_ru_show(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
static void
wv_local_show(struct net_device * dev)
{
- net_local *lp;
-
- lp = (net_local *)dev->priv;
+ net_local *lp = netdev_priv(dev);
printk(KERN_DEBUG "local:");
/*
static inline void
wv_init_info(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
+ kio_addr_t base = dev->base_addr;
psa_t psa;
int i;
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff */
- printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr",
+ printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr",
dev->name, base, dev->irq);
for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
#endif
- return(&((net_local *) dev->priv)->stats);
+ return(&((net_local *)netdev_priv(dev))->stats);
}
/*------------------------------------------------------------------*/
static void
wavelan_set_multicast_list(struct net_device * dev)
{
- net_local * lp = (net_local *) dev->priv;
+ net_local * lp = netdev_priv(dev);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
/*
* Frequency setting (for hardware able of it)
* It's a bit complicated and you don't really want to look into it...
- * (called in wavelan_ioctl)
*/
static inline int
wv_set_frequency(u_long base, /* i/o port of the card */
wl_his_gather(struct net_device * dev,
u_char * stats) /* Statistics to gather */
{
- net_local * lp = (net_local *) dev->priv;
+ net_local * lp = netdev_priv(dev);
u_char level = stats[0] & MMR_SIGNAL_LVL;
int i;
}
#endif /* HISTOGRAM */
-static inline int
-wl_netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- u32 ethcmd;
-
- if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
- return -EFAULT;
-
- switch (ethcmd) {
- case ETHTOOL_GDRVINFO: {
- struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-
- strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
- if (copy_to_user(useraddr, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- }
-
- return -EOPNOTSUPP;
+ strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1);
}
+static struct ethtool_ops ops = {
+ .get_drvinfo = wl_get_drvinfo
+};
+
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get protocol name
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
mm_t m;
unsigned long flags;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
int ret;
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
psa_t psa;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
/* Is the domain ID active ? */
wrqu->data.flags = lp->filter_domains;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
int ret = 0;
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
int ret = 0;
range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */
+ /* Event capability (kernel + driver) */
+ range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
+ IW_EVENT_CAPA_MASK(0x8B04) |
+ IW_EVENT_CAPA_MASK(0x8B06));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
union iwreq_data *wrqu,
char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ kio_addr_t base = dev->base_addr;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
/* Disable interrupts and save flags. */
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
/* Check the number of intervals. */
if (wrqu->data.length > 16) {
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev);
/* Set the number of intervals. */
wrqu->data.length = lp->his_number;
.num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
.num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
- .standard = (iw_handler *) wavelan_handler,
- .private = (iw_handler *) wavelan_private_handler,
- .private_args = (struct iw_priv_args *) wavelan_private_args,
- .spy_offset = ((void *) (&((net_local *) NULL)->spy_data) -
- (void *) NULL),
+ .standard = wavelan_handler,
+ .private = wavelan_private_handler,
+ .private_args = wavelan_private_args,
+ .get_wireless_stats = wavelan_get_wireless_stats,
};
-/*------------------------------------------------------------------*/
-/*
- * Perform ioctl : config & info stuff
- * This is here that are treated the wireless extensions (iwconfig)
- */
-static int
-wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
- struct ifreq * rq, /* Data passed */
- int cmd) /* Ioctl number */
-{
- int ret = 0;
-
-#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
-#endif
-
- /* Look what is the request */
- switch(cmd)
- {
- case SIOCETHTOOL:
- ret = wl_netdev_ethtool_ioctl(dev, rq->ifr_data);
- break;
-
- /* ------------------- OTHER IOCTL ------------------- */
-
- default:
- ret = -EOPNOTSUPP;
- }
-
-#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
-#endif
- return ret;
-}
-
/*------------------------------------------------------------------*/
/*
* Get wireless statistics
static iw_stats *
wavelan_get_wireless_stats(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *) dev->priv;
+ kio_addr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
mmr_t m;
iw_stats * wstats;
unsigned long flags;
int rfp, /* end of frame */
int wrap) /* start of buffer */
{
- ioaddr_t base = dev->base_addr;
+ kio_addr_t base = dev->base_addr;
int rp;
int len;
int fd_p,
int sksize)
{
- net_local * lp = (net_local *) dev->priv;
+ net_local * lp = netdev_priv(dev);
struct sk_buff * skb;
#ifdef DEBUG_RX_TRACE
static inline void
wv_packet_rcv(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *) dev->priv;
+ kio_addr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
int newrfp;
int rp;
int len;
void * buf,
short length)
{
- net_local * lp = (net_local *) dev->priv;
- ioaddr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
+ kio_addr_t base = dev->base_addr;
unsigned long flags;
int clen = length;
register u_short xmtdata_base = TX_BASE;
wavelan_packet_xmit(struct sk_buff * skb,
struct net_device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local * lp = netdev_priv(dev);
unsigned long flags;
#ifdef DEBUG_TX_TRACE
static inline int
wv_mmc_init(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
+ kio_addr_t base = dev->base_addr;
psa_t psa;
mmw_t m;
int configured;
static int
wv_ru_stop(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *) dev->priv;
+ kio_addr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
unsigned long flags;
int status;
int spin;
/* If there was a problem */
if(spin <= 0)
{
-#ifdef DEBUG_CONFIG_ERROR
+#ifdef DEBUG_CONFIG_ERRORS
printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
dev->name);
#endif
static int
wv_ru_start(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *) dev->priv;
+ kio_addr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
unsigned long flags;
#ifdef DEBUG_CONFIG_TRACE
static int
wv_82593_config(struct net_device * dev)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *) dev->priv;
+ kio_addr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
struct i82593_conf_block cfblk;
int ret = TRUE;
{
int i;
conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 };
- dev_link_t * link = ((net_local *) dev->priv)->link;
+ dev_link_t * link = ((net_local *)netdev_priv(dev))->link;
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
static int
wv_hw_config(struct net_device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- ioaddr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
+ kio_addr_t base = dev->base_addr;
unsigned long flags;
int ret = FALSE;
static inline void
wv_hw_reset(struct net_device * dev)
{
- net_local * lp = (net_local *) dev->priv;
+ net_local * lp = netdev_priv(dev);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
static inline int
wv_pcmcia_config(dev_link_t * link)
{
- client_handle_t handle;
+ client_handle_t handle = link->handle;
tuple_t tuple;
cisparse_t parse;
- struct net_device * dev;
+ struct net_device * dev = (struct net_device *) link->priv;
int i;
u_char buf[64];
win_req_t req;
memreq_t mem;
+ net_local * lp = netdev_priv(dev);
- handle = link->handle;
- dev = (struct net_device *) link->priv;
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link);
break;
}
- dev->mem_start = (u_long)ioremap(req.Base, req.Size);
+ lp->mem = ioremap(req.Base, req.Size);
+ dev->mem_start = (u_long)lp->mem;
dev->mem_end = dev->mem_start + req.Size;
mem.CardOffset = 0; mem.Page = 0;
netif_start_queue(dev);
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
- (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr);
+ printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART %p IRQ %d IOPORT 0x%x\n",
+ lp->mem, dev->irq, (u_int) dev->base_addr);
#endif
+ SET_NETDEV_DEV(dev, &handle_to_dev(handle));
i = register_netdev(dev);
if(i != 0)
{
return FALSE;
}
- strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
- link->dev = &((net_local *) dev->priv)->node;
+ strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name);
+ link->dev = &((net_local *) netdev_priv(dev))->node;
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
wv_pcmcia_release(dev_link_t *link)
{
struct net_device * dev = (struct net_device *) link->priv;
+ net_local * lp = netdev_priv(dev);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
#endif
/* Don't bother checking to see if these succeed or not */
- iounmap((u_char *)dev->mem_start);
+ iounmap(lp->mem);
pcmcia_release_window(link->win);
pcmcia_release_configuration(link->handle);
pcmcia_release_io(link->handle, &link->io);
{
struct net_device * dev;
net_local * lp;
- ioaddr_t base;
+ kio_addr_t base;
int status0;
u_int tx_status;
printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
#endif
- lp = (net_local *) dev->priv;
+ lp = netdev_priv(dev);
base = dev->base_addr;
#ifdef DEBUG_INTERRUPT_INFO
static void
wavelan_watchdog(struct net_device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- ioaddr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
+ kio_addr_t base = dev->base_addr;
unsigned long flags;
int aborted = FALSE;
static int
wavelan_open(struct net_device * dev)
{
- dev_link_t * link = ((net_local *) dev->priv)->link;
- net_local * lp = (net_local *)dev->priv;
- ioaddr_t base = dev->base_addr;
+ net_local * lp = netdev_priv(dev);
+ dev_link_t * link = lp->link;
+ kio_addr_t base = dev->base_addr;
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
static int
wavelan_close(struct net_device * dev)
{
- dev_link_t * link = ((net_local *) dev->priv)->link;
- ioaddr_t base = dev->base_addr;
+ dev_link_t * link = ((net_local *)netdev_priv(dev))->link;
+ kio_addr_t base = dev->base_addr;
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
dev_link_t * link; /* Info for cardmgr */
struct net_device * dev; /* Interface generic data */
net_local * lp; /* Interface specific data */
- int i, ret;
+ int ret;
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "-> wavelan_attach()\n");
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
- link->irq.IRQInfo2 = irq_mask;
- else
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = wavelan_interrupt;
/* General socket configuration */
}
link->priv = link->irq.Instance = dev;
- lp = dev->priv;
+ lp = netdev_priv(dev);
/* Init specific data */
lp->configured = 0;
/* Set the watchdog timer */
dev->tx_timeout = &wavelan_watchdog;
dev->watchdog_timeo = WATCHDOG_JIFFIES;
+ SET_ETHTOOL_OPS(dev, &ops);
#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
- dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
- dev->do_ioctl = wavelan_ioctl; /* old wireless extensions */
- dev->get_wireless_stats = wavelan_get_wireless_stats;
+ dev->wireless_handlers = &wavelan_handler_def;
+ lp->wireless_data.spy_data = &lp->spy_data;
+ dev->wireless_data = &lp->wireless_data;
#endif
/* Other specific data */
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
client_reg.EventMask =
CS_EVENT_REGISTRATION_COMPLETE |
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
if (link->dev)
unregister_netdev(dev);
link->dev = NULL;
- ((net_local *) dev->priv)->link = NULL;
- ((net_local *) dev->priv)->dev = NULL;
+ ((net_local *)netdev_priv(dev))->link = NULL;
+ ((net_local *)netdev_priv(dev))->dev = NULL;
free_netdev(dev);
}
kfree(link);