Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.30-rc3 224 lines 5.9 kB view raw
1/* 2 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/spinlock.h> 10#include <linux/poll.h> 11#include <linux/netdevice.h> 12#include <linux/types.h> 13#include <linux/skbuff.h> 14 15#include <net/mac80211.h> 16#include "rate.h" 17 18#include "rc80211_pid.h" 19 20static void rate_control_pid_event(struct rc_pid_event_buffer *buf, 21 enum rc_pid_event_type type, 22 union rc_pid_event_data *data) 23{ 24 struct rc_pid_event *ev; 25 unsigned long status; 26 27 spin_lock_irqsave(&buf->lock, status); 28 ev = &(buf->ring[buf->next_entry]); 29 buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE; 30 31 ev->timestamp = jiffies; 32 ev->id = buf->ev_count++; 33 ev->type = type; 34 ev->data = *data; 35 36 spin_unlock_irqrestore(&buf->lock, status); 37 38 wake_up_all(&buf->waitqueue); 39} 40 41void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, 42 struct ieee80211_tx_info *stat) 43{ 44 union rc_pid_event_data evd; 45 46 evd.flags = stat->flags; 47 memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); 48 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); 49} 50 51void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, 52 int index, int rate) 53{ 54 union rc_pid_event_data evd; 55 56 evd.index = index; 57 evd.rate = rate; 58 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd); 59} 60 61void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, 62 int index, int rate) 63{ 64 union rc_pid_event_data evd; 65 66 evd.index = index; 67 evd.rate = rate; 68 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd); 69} 70 71void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, 72 s32 pf_sample, s32 prop_err, 73 s32 int_err, s32 der_err) 74{ 75 union rc_pid_event_data evd; 76 77 evd.pf_sample = pf_sample; 78 evd.prop_err = prop_err; 79 evd.int_err = int_err; 80 evd.der_err = der_err; 81 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd); 82} 83 84static int rate_control_pid_events_open(struct inode *inode, struct file *file) 85{ 86 struct rc_pid_sta_info *sinfo = inode->i_private; 87 struct rc_pid_event_buffer *events = &sinfo->events; 88 struct rc_pid_events_file_info *file_info; 89 unsigned long status; 90 91 /* Allocate a state struct */ 92 file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); 93 if (file_info == NULL) 94 return -ENOMEM; 95 96 spin_lock_irqsave(&events->lock, status); 97 98 file_info->next_entry = events->next_entry; 99 file_info->events = events; 100 101 spin_unlock_irqrestore(&events->lock, status); 102 103 file->private_data = file_info; 104 105 return 0; 106} 107 108static int rate_control_pid_events_release(struct inode *inode, 109 struct file *file) 110{ 111 struct rc_pid_events_file_info *file_info = file->private_data; 112 113 kfree(file_info); 114 115 return 0; 116} 117 118static unsigned int rate_control_pid_events_poll(struct file *file, 119 poll_table *wait) 120{ 121 struct rc_pid_events_file_info *file_info = file->private_data; 122 123 poll_wait(file, &file_info->events->waitqueue, wait); 124 125 return POLLIN | POLLRDNORM; 126} 127 128#define RC_PID_PRINT_BUF_SIZE 64 129 130static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, 131 size_t length, loff_t *offset) 132{ 133 struct rc_pid_events_file_info *file_info = file->private_data; 134 struct rc_pid_event_buffer *events = file_info->events; 135 struct rc_pid_event *ev; 136 char pb[RC_PID_PRINT_BUF_SIZE]; 137 int ret; 138 int p; 139 unsigned long status; 140 141 /* Check if there is something to read. */ 142 if (events->next_entry == file_info->next_entry) { 143 if (file->f_flags & O_NONBLOCK) 144 return -EAGAIN; 145 146 /* Wait */ 147 ret = wait_event_interruptible(events->waitqueue, 148 events->next_entry != file_info->next_entry); 149 150 if (ret) 151 return ret; 152 } 153 154 /* Write out one event per call. I don't care whether it's a little 155 * inefficient, this is debugging code anyway. */ 156 spin_lock_irqsave(&events->lock, status); 157 158 /* Get an event */ 159 ev = &(events->ring[file_info->next_entry]); 160 file_info->next_entry = (file_info->next_entry + 1) % 161 RC_PID_EVENT_RING_SIZE; 162 163 /* Print information about the event. Note that userpace needs to 164 * provide large enough buffers. */ 165 length = length < RC_PID_PRINT_BUF_SIZE ? 166 length : RC_PID_PRINT_BUF_SIZE; 167 p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); 168 switch (ev->type) { 169 case RC_PID_EVENT_TYPE_TX_STATUS: 170 p += snprintf(pb + p, length - p, "tx_status %u %u", 171 !(ev->data.flags & IEEE80211_TX_STAT_ACK), 172 ev->data.tx_status.status.rates[0].idx); 173 break; 174 case RC_PID_EVENT_TYPE_RATE_CHANGE: 175 p += snprintf(pb + p, length - p, "rate_change %d %d", 176 ev->data.index, ev->data.rate); 177 break; 178 case RC_PID_EVENT_TYPE_TX_RATE: 179 p += snprintf(pb + p, length - p, "tx_rate %d %d", 180 ev->data.index, ev->data.rate); 181 break; 182 case RC_PID_EVENT_TYPE_PF_SAMPLE: 183 p += snprintf(pb + p, length - p, 184 "pf_sample %d %d %d %d", 185 ev->data.pf_sample, ev->data.prop_err, 186 ev->data.int_err, ev->data.der_err); 187 break; 188 } 189 p += snprintf(pb + p, length - p, "\n"); 190 191 spin_unlock_irqrestore(&events->lock, status); 192 193 if (copy_to_user(buf, pb, p)) 194 return -EFAULT; 195 196 return p; 197} 198 199#undef RC_PID_PRINT_BUF_SIZE 200 201static struct file_operations rc_pid_fop_events = { 202 .owner = THIS_MODULE, 203 .read = rate_control_pid_events_read, 204 .poll = rate_control_pid_events_poll, 205 .open = rate_control_pid_events_open, 206 .release = rate_control_pid_events_release, 207}; 208 209void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, 210 struct dentry *dir) 211{ 212 struct rc_pid_sta_info *spinfo = priv_sta; 213 214 spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO, 215 dir, spinfo, 216 &rc_pid_fop_events); 217} 218 219void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta) 220{ 221 struct rc_pid_sta_info *spinfo = priv_sta; 222 223 debugfs_remove(spinfo->events_entry); 224}