1/* Copyright (C) 2010 - 2013 UNISYS CORPORATION 2 * All rights reserved. 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 as published by 6 * the Free Software Foundation; either version 2 of the License, or (at 7 * your option) any later version. 8 * 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, GOOD TITLE or 12 * NON INFRINGEMENT. See the GNU General Public License for more 13 * details. 14 */ 15 16/** @file ********************************************************************* 17 * 18 * Handle procfs-specific tasks. 19 * Note that this file does not know about any module-specific things, nor 20 * does it know anything about what information to reveal as part of the proc 21 * entries. The 2 functions that take care of displaying device and 22 * driver specific information are passed as parameters to 23 * visor_easyproc_InitDriver(). 24 * 25 * void show_device_info(struct seq_file *seq, void *p); 26 * void show_driver_info(struct seq_file *seq); 27 * 28 * The second parameter to show_device_info is actually a pointer to the 29 * device-specific info to show. It is the context that was originally 30 * passed to visor_easyproc_InitDevice(). 31 * 32 ****************************************************************************** 33 */ 34 35#include <linux/proc_fs.h> 36 37#include "uniklog.h" 38#include "timskmod.h" 39#include "easyproc.h" 40 41#define MYDRVNAME "easyproc" 42 43 44 45/* 46 * /proc/<ProcId> ProcDir 47 * /proc/<ProcId>/driver ProcDriverDir 48 * /proc/<ProcId>/driver/diag ProcDriverDiagFile 49 * /proc/<ProcId>/device ProcDeviceDir 50 * /proc/<ProcId>/device/0 procDevicexDir 51 * /proc/<ProcId>/device/0/diag procDevicexDiagFile 52 */ 53 54 55static ssize_t proc_write_device(struct file *file, const char __user *buffer, 56 size_t count, loff_t *ppos); 57static ssize_t proc_write_driver(struct file *file, const char __user *buffer, 58 size_t count, loff_t *ppos); 59 60static struct proc_dir_entry * 61 createProcDir(char *name, struct proc_dir_entry *parent) 62{ 63 struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent); 64 65 if (p == NULL) 66 ERRDRV("failed to create /proc directory %s", name); 67 return p; 68} 69 70static int seq_show_driver(struct seq_file *seq, void *offset); 71static int proc_open_driver(struct inode *inode, struct file *file) 72{ 73 return single_open(file, seq_show_driver, PDE_DATA(inode)); 74} 75static const struct file_operations proc_fops_driver = { 76 .open = proc_open_driver, 77 .read = seq_read, 78 .write = proc_write_driver, 79 .llseek = seq_lseek, 80 .release = single_release, 81}; 82 83static int seq_show_device(struct seq_file *seq, void *offset); 84static int seq_show_device_property(struct seq_file *seq, void *offset); 85static int proc_open_device(struct inode *inode, struct file *file) 86{ 87 return single_open(file, seq_show_device, PDE_DATA(inode)); 88} 89static const struct file_operations proc_fops_device = { 90 .open = proc_open_device, 91 .read = seq_read, 92 .write = proc_write_device, 93 .llseek = seq_lseek, 94 .release = single_release, 95}; 96static int proc_open_device_property(struct inode *inode, struct file *file) 97{ 98 return single_open(file, seq_show_device_property, PDE_DATA(inode)); 99} 100static const struct file_operations proc_fops_device_property = { 101 .open = proc_open_device_property, 102 .read = seq_read, 103 .llseek = seq_lseek, 104 .release = single_release, 105}; 106 107 108 109void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver, 110 char *procId, 111 void (*show_driver_info)(struct seq_file *), 112 void (*show_device_info)(struct seq_file *, 113 void *)) 114{ 115 memset(pdriver, 0, sizeof(struct easyproc_driver_info)); 116 pdriver->ProcId = procId; 117 if (pdriver->ProcId == NULL) 118 ERRDRV("ProcId cannot be NULL (trouble ahead)!"); 119 pdriver->Show_driver_info = show_driver_info; 120 pdriver->Show_device_info = show_device_info; 121 if (pdriver->ProcDir == NULL) 122 pdriver->ProcDir = createProcDir(pdriver->ProcId, NULL); 123 if ((pdriver->ProcDir != NULL) && (pdriver->ProcDriverDir == NULL)) 124 pdriver->ProcDriverDir = createProcDir("driver", 125 pdriver->ProcDir); 126 if ((pdriver->ProcDir != NULL) && (pdriver->ProcDeviceDir == NULL)) 127 pdriver->ProcDeviceDir = createProcDir("device", 128 pdriver->ProcDir); 129 if ((pdriver->ProcDriverDir != NULL) && 130 (pdriver->ProcDriverDiagFile == NULL)) { 131 pdriver->ProcDriverDiagFile = 132 proc_create_data("diag", 0, 133 pdriver->ProcDriverDir, 134 &proc_fops_driver, pdriver); 135 if (pdriver->ProcDriverDiagFile == NULL) 136 ERRDRV("failed to register /proc/%s/driver/diag entry", 137 pdriver->ProcId); 138 } 139} 140EXPORT_SYMBOL_GPL(visor_easyproc_InitDriver); 141 142 143 144void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver, 145 char *procId, 146 void (*show_driver_info)(struct seq_file *), 147 void (*show_device_info)(struct seq_file *, 148 void *), 149 void (*write_driver_info)(char *buf, 150 size_t count, 151 loff_t *ppos), 152 void (*write_device_info)(char *buf, 153 size_t count, 154 loff_t *ppos, 155 void *p)) 156{ 157 visor_easyproc_InitDriver(pdriver, procId, 158 show_driver_info, show_device_info); 159 pdriver->Write_driver_info = write_driver_info; 160 pdriver->Write_device_info = write_device_info; 161} 162EXPORT_SYMBOL_GPL(visor_easyproc_InitDriverEx); 163 164 165 166void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver) 167{ 168 if (pdriver->ProcDriverDiagFile != NULL) { 169 remove_proc_entry("diag", pdriver->ProcDriverDir); 170 pdriver->ProcDriverDiagFile = NULL; 171 } 172 if (pdriver->ProcDriverDir != NULL) { 173 remove_proc_entry("driver", pdriver->ProcDir); 174 pdriver->ProcDriverDir = NULL; 175 } 176 if (pdriver->ProcDeviceDir != NULL) { 177 remove_proc_entry("device", pdriver->ProcDir); 178 pdriver->ProcDeviceDir = NULL; 179 } 180 if (pdriver->ProcDir != NULL) { 181 remove_proc_entry(pdriver->ProcId, NULL); 182 pdriver->ProcDir = NULL; 183 } 184 pdriver->ProcId = NULL; 185 pdriver->Show_driver_info = NULL; 186 pdriver->Show_device_info = NULL; 187 pdriver->Write_driver_info = NULL; 188 pdriver->Write_device_info = NULL; 189} 190EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDriver); 191 192 193 194void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver, 195 struct easyproc_device_info *p, int devno, 196 void *devdata) 197{ 198 if ((pdriver->ProcDeviceDir != NULL) && (p->procDevicexDir == NULL)) { 199 char s[29]; 200 201 sprintf(s, "%d", devno); 202 p->procDevicexDir = createProcDir(s, pdriver->ProcDeviceDir); 203 p->devno = devno; 204 } 205 p->devdata = devdata; 206 p->pdriver = pdriver; 207 p->devno = devno; 208 if ((p->procDevicexDir != NULL) && (p->procDevicexDiagFile == NULL)) { 209 p->procDevicexDiagFile = 210 proc_create_data("diag", 0, p->procDevicexDir, 211 &proc_fops_device, p); 212 if (p->procDevicexDiagFile == NULL) 213 ERRDEVX(devno, "failed to register /proc/%s/device/%d/diag entry", 214 pdriver->ProcId, devno 215 ); 216 } 217 memset(&(p->device_property_info[0]), 0, 218 sizeof(p->device_property_info)); 219} 220EXPORT_SYMBOL_GPL(visor_easyproc_InitDevice); 221 222 223 224void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p, 225 void (*show_property_info) 226 (struct seq_file *, void *), 227 char *property_name) 228{ 229 size_t i; 230 struct easyproc_device_property_info *px = NULL; 231 232 if (p->procDevicexDir == NULL) { 233 ERRDRV("state error"); 234 return; 235 } 236 for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) { 237 if (p->device_property_info[i].procEntry == NULL) { 238 px = &(p->device_property_info[i]); 239 break; 240 } 241 } 242 if (!px) { 243 ERRDEVX(p->devno, "too many device properties"); 244 return; 245 } 246 px->devdata = p->devdata; 247 px->pdriver = p->pdriver; 248 px->procEntry = proc_create_data(property_name, 0, p->procDevicexDir, 249 &proc_fops_device_property, px); 250 if (strlen(property_name)+1 > sizeof(px->property_name)) { 251 ERRDEVX(p->devno, "device property name %s too long", 252 property_name); 253 return; 254 } 255 strcpy(px->property_name, property_name); 256 if (px->procEntry == NULL) { 257 ERRDEVX(p->devno, "failed to register /proc/%s/device/%d/%s entry", 258 p->pdriver->ProcId, p->devno, property_name 259 ); 260 return; 261 } 262 px->show_device_property_info = show_property_info; 263} 264EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty); 265 266 267 268void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver, 269 struct easyproc_device_info *p, int devno) 270{ 271 size_t i; 272 273 for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) { 274 if (p->device_property_info[i].procEntry != NULL) { 275 struct easyproc_device_property_info *px = 276 &(p->device_property_info[i]); 277 remove_proc_entry(px->property_name, p->procDevicexDir); 278 px->procEntry = NULL; 279 } 280 } 281 if (p->procDevicexDiagFile != NULL) { 282 remove_proc_entry("diag", p->procDevicexDir); 283 p->procDevicexDiagFile = NULL; 284 } 285 if (p->procDevicexDir != NULL) { 286 char s[29]; 287 288 sprintf(s, "%d", devno); 289 remove_proc_entry(s, pdriver->ProcDeviceDir); 290 p->procDevicexDir = NULL; 291 } 292 p->devdata = NULL; 293 p->pdriver = NULL; 294} 295EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDevice); 296 297 298 299static int seq_show_driver(struct seq_file *seq, void *offset) 300{ 301 struct easyproc_driver_info *p = 302 (struct easyproc_driver_info *)(seq->private); 303 if (!p) 304 return 0; 305 (*(p->Show_driver_info))(seq); 306 return 0; 307} 308 309 310 311static int seq_show_device(struct seq_file *seq, void *offset) 312{ 313 struct easyproc_device_info *p = 314 (struct easyproc_device_info *)(seq->private); 315 if ((!p) || (!(p->pdriver))) 316 return 0; 317 (*(p->pdriver->Show_device_info))(seq, p->devdata); 318 return 0; 319} 320 321 322 323static int seq_show_device_property(struct seq_file *seq, void *offset) 324{ 325 struct easyproc_device_property_info *p = 326 (struct easyproc_device_property_info *)(seq->private); 327 if ((!p) || (!(p->show_device_property_info))) 328 return 0; 329 (*(p->show_device_property_info))(seq, p->devdata); 330 return 0; 331} 332 333 334 335static ssize_t proc_write_driver(struct file *file, const char __user *buffer, 336 size_t count, loff_t *ppos) 337{ 338 struct seq_file *seq = (struct seq_file *)file->private_data; 339 struct easyproc_driver_info *p = NULL; 340 char local_buf[256]; 341 342 if (seq == NULL) 343 return 0; 344 p = (struct easyproc_driver_info *)(seq->private); 345 if ((!p) || (!(p->Write_driver_info))) 346 return 0; 347 if (count >= sizeof(local_buf)) 348 return -ENOMEM; 349 if (copy_from_user(local_buf, buffer, count)) 350 return -EFAULT; 351 local_buf[count] = '\0'; /* be friendly */ 352 (*(p->Write_driver_info))(local_buf, count, ppos); 353 return count; 354} 355 356 357 358static ssize_t proc_write_device(struct file *file, const char __user *buffer, 359 size_t count, loff_t *ppos) 360{ 361 struct seq_file *seq = (struct seq_file *)file->private_data; 362 struct easyproc_device_info *p = NULL; 363 char local_buf[256]; 364 365 if (seq == NULL) 366 return 0; 367 p = (struct easyproc_device_info *)(seq->private); 368 if ((!p) || (!(p->pdriver)) || (!(p->pdriver->Write_device_info))) 369 return 0; 370 if (count >= sizeof(local_buf)) 371 return -ENOMEM; 372 if (copy_from_user(local_buf, buffer, count)) 373 return -EFAULT; 374 local_buf[count] = '\0'; /* be friendly */ 375 (*(p->pdriver->Write_device_info))(local_buf, count, ppos, p->devdata); 376 return count; 377} 378