2023-08-23 12:29:12 +03:00
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2015-07-30 22:17:43 +03:00
/*
2016-02-15 07:22:17 +03:00
* Copyright ( c ) 2015 , 2016 Intel Corporation .
2015-07-30 22:17:43 +03:00
*/
# include <linux/cdev.h>
# include <linux/device.h>
# include <linux/fs.h>
# include "hfi.h"
# include "device.h"
2023-08-04 18:05:28 +03:00
static char * hfi1_devnode ( const struct device * dev , umode_t * mode )
{
if ( mode )
* mode = 0600 ;
return kasprintf ( GFP_KERNEL , " %s " , dev_name ( dev ) ) ;
}
static const struct class class = {
. name = " hfi1 " ,
. devnode = hfi1_devnode ,
} ;
static char * hfi1_user_devnode ( const struct device * dev , umode_t * mode )
{
if ( mode )
* mode = 0666 ;
return kasprintf ( GFP_KERNEL , " %s " , dev_name ( dev ) ) ;
}
static const struct class user_class = {
. name = " hfi1_user " ,
. devnode = hfi1_user_devnode ,
} ;
2015-07-30 22:17:43 +03:00
static dev_t hfi1_dev ;
int hfi1_cdev_init ( int minor , const char * name ,
const struct file_operations * fops ,
2015-09-17 20:47:49 +03:00
struct cdev * cdev , struct device * * devp ,
2016-05-19 15:26:44 +03:00
bool user_accessible ,
struct kobject * parent )
2015-07-30 22:17:43 +03:00
{
const dev_t dev = MKDEV ( MAJOR ( hfi1_dev ) , minor ) ;
struct device * device = NULL ;
int ret ;
cdev_init ( cdev , fops ) ;
cdev - > owner = THIS_MODULE ;
2017-03-17 21:48:16 +03:00
cdev_set_parent ( cdev , parent ) ;
2015-07-30 22:17:43 +03:00
kobject_set_name ( & cdev - > kobj , name ) ;
ret = cdev_add ( cdev , dev , 1 ) ;
if ( ret < 0 ) {
pr_err ( " Could not add cdev for minor %d, %s (err %d) \n " ,
minor , name , - ret ) ;
goto done ;
}
2015-09-17 20:47:49 +03:00
if ( user_accessible )
2023-08-04 18:05:28 +03:00
device = device_create ( & user_class , NULL , dev , NULL , " %s " , name ) ;
2015-09-17 20:47:49 +03:00
else
2023-08-04 18:05:28 +03:00
device = device_create ( & class , NULL , dev , NULL , " %s " , name ) ;
2015-09-17 20:47:49 +03:00
2016-05-19 15:22:03 +03:00
if ( IS_ERR ( device ) ) {
ret = PTR_ERR ( device ) ;
device = NULL ;
pr_err ( " Could not create device for minor %d, %s (err %d) \n " ,
minor , name , - ret ) ;
cdev_del ( cdev ) ;
}
2015-07-30 22:17:43 +03:00
done :
* devp = device ;
return ret ;
}
void hfi1_cdev_cleanup ( struct cdev * cdev , struct device * * devp )
{
struct device * device = * devp ;
if ( device ) {
device_unregister ( device ) ;
* devp = NULL ;
cdev_del ( cdev ) ;
}
}
static const char * hfi1_class_name = " hfi1 " ;
const char * class_name ( void )
{
return hfi1_class_name ;
}
int __init dev_init ( void )
{
int ret ;
ret = alloc_chrdev_region ( & hfi1_dev , 0 , HFI1_NMINORS , DRIVER_NAME ) ;
if ( ret < 0 ) {
pr_err ( " Could not allocate chrdev region (err %d) \n " , - ret ) ;
goto done ;
}
2023-08-04 18:05:28 +03:00
ret = class_register ( & class ) ;
if ( ret ) {
2015-07-30 22:17:43 +03:00
pr_err ( " Could not create device class (err %d) \n " , - ret ) ;
unregister_chrdev_region ( hfi1_dev , HFI1_NMINORS ) ;
2015-09-17 20:47:49 +03:00
goto done ;
2015-07-30 22:17:43 +03:00
}
2015-09-17 20:47:49 +03:00
2023-08-04 18:05:28 +03:00
ret = class_register ( & user_class ) ;
if ( ret ) {
2015-09-17 20:47:49 +03:00
pr_err ( " Could not create device class for user accessible files (err %d) \n " ,
- ret ) ;
2023-08-04 18:05:28 +03:00
class_unregister ( & class ) ;
2015-09-17 20:47:49 +03:00
unregister_chrdev_region ( hfi1_dev , HFI1_NMINORS ) ;
goto done ;
}
2015-07-30 22:17:43 +03:00
done :
return ret ;
}
void dev_cleanup ( void )
{
2023-08-04 18:05:28 +03:00
class_unregister ( & class ) ;
class_unregister ( & user_class ) ;
2015-07-30 22:17:43 +03:00
unregister_chrdev_region ( hfi1_dev , HFI1_NMINORS ) ;
}