2019-03-12 01:10:41 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-03-27 19:29:53 +04:00
/*
2019-03-12 01:10:44 +03:00
* Copyright ( c ) 2012 - 2019 , Intel Corporation . All rights reserved .
2013-03-27 19:29:53 +04:00
* Intel Management Engine Interface ( Intel MEI ) Linux driver
*/
# include <linux/module.h>
# include <linux/device.h>
# include <linux/kernel.h>
2017-02-02 21:15:33 +03:00
# include <linux/sched/signal.h>
2013-03-27 19:29:53 +04:00
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/mutex.h>
# include <linux/interrupt.h>
# include <linux/mei_cl_bus.h>
# include "mei_dev.h"
2013-03-27 19:29:55 +04:00
# include "client.h"
2013-03-27 19:29:53 +04:00
# define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
2015-07-23 15:08:35 +03:00
/**
* __mei_cl_send - internal client send ( write )
*
* @ cl : host client
* @ buf : buffer to send
* @ length : buffer length
2016-11-08 19:26:08 +03:00
* @ mode : sending mode
2015-07-23 15:08:35 +03:00
*
* Return : written size bytes or < 0 on error
*/
ssize_t __mei_cl_send ( struct mei_cl * cl , u8 * buf , size_t length ,
2016-11-08 19:26:08 +03:00
unsigned int mode )
2013-03-27 19:29:53 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_device * bus ;
2016-02-11 00:57:26 +03:00
struct mei_cl_cb * cb ;
2015-07-23 15:08:35 +03:00
ssize_t rets ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
if ( WARN_ON ( ! cl | | ! cl - > dev ) )
return - ENODEV ;
2015-05-07 15:54:02 +03:00
2015-07-23 15:08:35 +03:00
bus = cl - > dev ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
mutex_lock ( & bus - > device_lock ) ;
2016-02-08 00:35:32 +03:00
if ( bus - > dev_state ! = MEI_DEV_ENABLED ) {
rets = - ENODEV ;
goto out ;
}
2015-07-23 15:08:35 +03:00
if ( ! mei_cl_is_connected ( cl ) ) {
rets = - ENODEV ;
goto out ;
}
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
/* Check if we have an ME client device */
if ( ! mei_me_cl_is_active ( cl - > me_cl ) ) {
rets = - ENOTTY ;
goto out ;
}
2015-05-07 15:54:02 +03:00
2015-07-23 15:08:35 +03:00
if ( length > mei_cl_mtu ( cl ) ) {
rets = - EFBIG ;
goto out ;
}
2013-03-27 19:29:53 +04:00
2018-02-25 21:07:05 +03:00
while ( cl - > tx_cb_queued > = bus - > tx_queue_limit ) {
mutex_unlock ( & bus - > device_lock ) ;
rets = wait_event_interruptible ( cl - > tx_wait ,
cl - > writing_state = = MEI_WRITE_COMPLETE | |
( ! mei_cl_is_connected ( cl ) ) ) ;
mutex_lock ( & bus - > device_lock ) ;
if ( rets ) {
if ( signal_pending ( current ) )
rets = - EINTR ;
goto out ;
}
if ( ! mei_cl_is_connected ( cl ) ) {
rets = - ENODEV ;
goto out ;
}
}
2015-07-23 15:08:35 +03:00
cb = mei_cl_alloc_cb ( cl , length , MEI_FOP_WRITE , NULL ) ;
if ( ! cb ) {
rets = - ENOMEM ;
goto out ;
2013-03-27 19:29:53 +04:00
}
2016-11-08 19:26:08 +03:00
cb - > internal = ! ! ( mode & MEI_CL_IO_TX_INTERNAL ) ;
cb - > blocking = ! ! ( mode & MEI_CL_IO_TX_BLOCKING ) ;
2015-07-23 15:08:35 +03:00
memcpy ( cb - > buf . data , buf , length ) ;
2016-11-08 19:26:08 +03:00
rets = mei_cl_write ( cl , cb ) ;
2015-07-23 15:08:35 +03:00
out :
mutex_unlock ( & bus - > device_lock ) ;
return rets ;
2013-03-27 19:29:53 +04:00
}
2015-07-23 15:08:35 +03:00
/**
* __mei_cl_recv - internal client receive ( read )
*
* @ cl : host client
2015-10-13 15:02:40 +03:00
* @ buf : buffer to receive
2015-07-23 15:08:35 +03:00
* @ length : buffer length
2016-12-03 01:15:25 +03:00
* @ mode : io mode
2018-06-25 00:11:40 +03:00
* @ timeout : recv timeout , 0 for infinite timeout
2015-07-23 15:08:35 +03:00
*
* Return : read size in bytes of < 0 on error
*/
2016-12-03 01:15:25 +03:00
ssize_t __mei_cl_recv ( struct mei_cl * cl , u8 * buf , size_t length ,
2018-06-25 00:11:40 +03:00
unsigned int mode , unsigned long timeout )
2013-03-27 19:29:53 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_device * bus ;
struct mei_cl_cb * cb ;
size_t r_length ;
ssize_t rets ;
2016-12-03 01:15:25 +03:00
bool nonblock = ! ! ( mode & MEI_CL_IO_RX_NONBLOCK ) ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
if ( WARN_ON ( ! cl | | ! cl - > dev ) )
2013-03-27 19:29:53 +04:00
return - ENODEV ;
2015-07-23 15:08:35 +03:00
bus = cl - > dev ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
mutex_lock ( & bus - > device_lock ) ;
2016-02-08 00:35:32 +03:00
if ( bus - > dev_state ! = MEI_DEV_ENABLED ) {
rets = - ENODEV ;
goto out ;
}
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
cb = mei_cl_read_cb ( cl , NULL ) ;
if ( cb )
goto copy ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
rets = mei_cl_read_start ( cl , length , NULL ) ;
if ( rets & & rets ! = - EBUSY )
goto out ;
2013-03-27 19:29:53 +04:00
2016-12-03 01:15:25 +03:00
if ( nonblock ) {
rets = - EAGAIN ;
goto out ;
}
2015-07-23 15:08:35 +03:00
/* wait on event only if there is no other waiter */
2016-06-16 17:58:54 +03:00
/* synchronized under device mutex */
if ( ! waitqueue_active ( & cl - > rx_wait ) ) {
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
mutex_unlock ( & bus - > device_lock ) ;
2013-03-27 19:29:55 +04:00
2018-06-25 00:11:40 +03:00
if ( timeout ) {
rets = wait_event_interruptible_timeout
( cl - > rx_wait ,
( ! list_empty ( & cl - > rd_completed ) ) | |
( ! mei_cl_is_connected ( cl ) ) ,
msecs_to_jiffies ( timeout ) ) ;
if ( rets = = 0 )
return - ETIME ;
if ( rets < 0 ) {
if ( signal_pending ( current ) )
return - EINTR ;
return - ERESTARTSYS ;
}
} else {
if ( wait_event_interruptible
( cl - > rx_wait ,
( ! list_empty ( & cl - > rd_completed ) ) | |
( ! mei_cl_is_connected ( cl ) ) ) ) {
if ( signal_pending ( current ) )
return - EINTR ;
return - ERESTARTSYS ;
}
2015-07-23 15:08:35 +03:00
}
mutex_lock ( & bus - > device_lock ) ;
if ( ! mei_cl_is_connected ( cl ) ) {
2016-06-23 00:25:31 +03:00
rets = - ENODEV ;
2015-07-23 15:08:35 +03:00
goto out ;
}
2013-03-27 19:29:53 +04:00
}
2015-07-23 15:08:35 +03:00
cb = mei_cl_read_cb ( cl , NULL ) ;
if ( ! cb ) {
rets = 0 ;
goto out ;
}
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
copy :
if ( cb - > status ) {
rets = cb - > status ;
goto free ;
}
2015-05-07 15:54:03 +03:00
2015-07-23 15:08:35 +03:00
r_length = min_t ( size_t , length , cb - > buf_idx ) ;
memcpy ( buf , cb - > buf . data , r_length ) ;
rets = r_length ;
2015-05-07 15:54:03 +03:00
2015-07-23 15:08:35 +03:00
free :
mei_io_cb_free ( cb ) ;
out :
mutex_unlock ( & bus - > device_lock ) ;
return rets ;
2015-05-07 15:54:03 +03:00
}
2015-07-23 15:08:35 +03:00
/**
2015-09-10 10:18:05 +03:00
* mei_cldev_send - me device send ( write )
2015-07-23 15:08:35 +03:00
*
* @ cldev : me client device
* @ buf : buffer to send
* @ length : buffer length
*
* Return : written size in bytes or < 0 on error
*/
2015-09-10 10:18:05 +03:00
ssize_t mei_cldev_send ( struct mei_cl_device * cldev , u8 * buf , size_t length )
2015-05-07 15:54:03 +03:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl * cl = cldev - > cl ;
2015-05-07 15:54:03 +03:00
2016-11-08 19:26:08 +03:00
return __mei_cl_send ( cl , buf , length , MEI_CL_IO_TX_BLOCKING ) ;
2015-05-07 15:54:03 +03:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_send ) ;
2015-05-07 15:54:03 +03:00
2016-12-03 01:15:25 +03:00
/**
* mei_cldev_recv_nonblock - non block client receive ( read )
*
* @ cldev : me client device
* @ buf : buffer to receive
* @ length : buffer length
*
* Return : read size in bytes of < 0 on error
* - EAGAIN if function will block .
*/
ssize_t mei_cldev_recv_nonblock ( struct mei_cl_device * cldev , u8 * buf ,
size_t length )
{
struct mei_cl * cl = cldev - > cl ;
2018-06-25 00:11:40 +03:00
return __mei_cl_recv ( cl , buf , length , MEI_CL_IO_RX_NONBLOCK , 0 ) ;
2016-12-03 01:15:25 +03:00
}
EXPORT_SYMBOL_GPL ( mei_cldev_recv_nonblock ) ;
2015-07-23 15:08:35 +03:00
/**
2015-09-10 10:18:05 +03:00
* mei_cldev_recv - client receive ( read )
2015-07-23 15:08:35 +03:00
*
* @ cldev : me client device
2015-10-13 15:02:40 +03:00
* @ buf : buffer to receive
2015-07-23 15:08:35 +03:00
* @ length : buffer length
*
* Return : read size in bytes of < 0 on error
*/
2015-09-10 10:18:05 +03:00
ssize_t mei_cldev_recv ( struct mei_cl_device * cldev , u8 * buf , size_t length )
2013-03-27 19:29:53 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl * cl = cldev - > cl ;
2013-03-27 19:29:53 +04:00
2018-06-25 00:11:40 +03:00
return __mei_cl_recv ( cl , buf , length , 0 , 0 ) ;
2013-03-27 19:29:53 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_recv ) ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
/**
2016-11-16 23:51:29 +03:00
* mei_cl_bus_rx_work - dispatch rx event for a bus device
2015-07-23 15:08:35 +03:00
*
* @ work : work
*/
2016-11-16 23:51:29 +03:00
static void mei_cl_bus_rx_work ( struct work_struct * work )
2013-03-27 19:29:53 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev ;
2016-05-04 01:54:21 +03:00
struct mei_device * bus ;
2015-05-07 15:54:02 +03:00
2016-11-16 23:51:29 +03:00
cldev = container_of ( work , struct mei_cl_device , rx_work ) ;
2015-05-07 15:54:03 +03:00
2016-05-04 01:54:21 +03:00
bus = cldev - > bus ;
2016-11-16 23:51:29 +03:00
if ( cldev - > rx_cb )
cldev - > rx_cb ( cldev ) ;
2015-05-07 15:54:03 +03:00
2016-11-16 23:51:29 +03:00
mutex_lock ( & bus - > device_lock ) ;
mei_cl_read_start ( cldev - > cl , mei_cl_mtu ( cldev - > cl ) , NULL ) ;
mutex_unlock ( & bus - > device_lock ) ;
}
2013-03-27 19:29:53 +04:00
2016-11-16 23:51:29 +03:00
/**
* mei_cl_bus_notif_work - dispatch FW notif event for a bus device
*
* @ work : work
*/
static void mei_cl_bus_notif_work ( struct work_struct * work )
{
struct mei_cl_device * cldev ;
cldev = container_of ( work , struct mei_cl_device , notif_work ) ;
if ( cldev - > notif_cb )
cldev - > notif_cb ( cldev ) ;
2015-07-26 09:54:23 +03:00
}
/**
* mei_cl_bus_notify_event - schedule notify cb on bus client
*
* @ cl : host client
2016-02-08 00:35:31 +03:00
*
* Return : true if event was scheduled
* false if the client is not waiting for event
2015-07-26 09:54:23 +03:00
*/
2016-02-08 00:35:31 +03:00
bool mei_cl_bus_notify_event ( struct mei_cl * cl )
2015-07-26 09:54:23 +03:00
{
struct mei_cl_device * cldev = cl - > cldev ;
2016-11-16 23:51:29 +03:00
if ( ! cldev | | ! cldev - > notif_cb )
2016-02-08 00:35:31 +03:00
return false ;
2015-07-26 09:54:23 +03:00
if ( ! cl - > notify_ev )
2016-02-08 00:35:31 +03:00
return false ;
2015-07-26 09:54:23 +03:00
2016-11-16 23:51:29 +03:00
schedule_work ( & cldev - > notif_work ) ;
2015-07-26 09:54:23 +03:00
cl - > notify_ev = false ;
2016-02-08 00:35:31 +03:00
return true ;
2013-03-27 19:29:53 +04:00
}
2015-07-23 15:08:35 +03:00
/**
2016-11-16 23:51:29 +03:00
* mei_cl_bus_rx_event - schedule rx event
2015-07-23 15:08:35 +03:00
*
* @ cl : host client
2016-02-08 00:35:30 +03:00
*
* Return : true if event was scheduled
* false if the client is not waiting for event
2015-07-23 15:08:35 +03:00
*/
2016-02-08 00:35:30 +03:00
bool mei_cl_bus_rx_event ( struct mei_cl * cl )
2013-03-27 19:29:53 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev = cl - > cldev ;
2015-05-04 09:43:54 +03:00
2016-11-16 23:51:29 +03:00
if ( ! cldev | | ! cldev - > rx_cb )
2016-02-08 00:35:30 +03:00
return false ;
2015-07-26 09:54:23 +03:00
2016-11-16 23:51:29 +03:00
schedule_work ( & cldev - > rx_work ) ;
2016-02-08 00:35:30 +03:00
return true ;
2013-03-27 19:29:56 +04:00
}
2015-05-04 09:43:54 +03:00
2015-07-23 15:08:35 +03:00
/**
2016-11-16 23:51:29 +03:00
* mei_cldev_register_rx_cb - register Rx event callback
2015-07-23 15:08:35 +03:00
*
* @ cldev : me client devices
2016-11-16 23:51:29 +03:00
* @ rx_cb : callback function
2015-07-23 15:08:35 +03:00
*
* Return : 0 on success
* - EALREADY if an callback is already registered
* < 0 on other errors
*/
2016-11-16 23:51:29 +03:00
int mei_cldev_register_rx_cb ( struct mei_cl_device * cldev , mei_cldev_cb_t rx_cb )
2013-03-27 19:29:53 +04:00
{
2016-05-04 01:54:21 +03:00
struct mei_device * bus = cldev - > bus ;
2015-07-23 15:08:38 +03:00
int ret ;
2016-11-16 23:51:29 +03:00
if ( ! rx_cb )
return - EINVAL ;
if ( cldev - > rx_cb )
2015-07-23 15:08:35 +03:00
return - EALREADY ;
2013-03-27 19:29:53 +04:00
2016-11-16 23:51:29 +03:00
cldev - > rx_cb = rx_cb ;
INIT_WORK ( & cldev - > rx_work , mei_cl_bus_rx_work ) ;
2013-03-27 19:29:56 +04:00
2016-11-16 23:51:29 +03:00
mutex_lock ( & bus - > device_lock ) ;
ret = mei_cl_read_start ( cldev - > cl , mei_cl_mtu ( cldev - > cl ) , NULL ) ;
mutex_unlock ( & bus - > device_lock ) ;
if ( ret & & ret ! = - EBUSY )
return ret ;
2015-07-26 09:54:23 +03:00
2016-11-16 23:51:29 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( mei_cldev_register_rx_cb ) ;
/**
* mei_cldev_register_notif_cb - register FW notification event callback
*
* @ cldev : me client devices
* @ notif_cb : callback function
*
* Return : 0 on success
* - EALREADY if an callback is already registered
* < 0 on other errors
*/
int mei_cldev_register_notif_cb ( struct mei_cl_device * cldev ,
mei_cldev_cb_t notif_cb )
{
struct mei_device * bus = cldev - > bus ;
int ret ;
if ( ! notif_cb )
return - EINVAL ;
if ( cldev - > notif_cb )
return - EALREADY ;
cldev - > notif_cb = notif_cb ;
INIT_WORK ( & cldev - > notif_work , mei_cl_bus_notif_work ) ;
mutex_lock ( & bus - > device_lock ) ;
ret = mei_cl_notify_request ( cldev - > cl , NULL , 1 ) ;
mutex_unlock ( & bus - > device_lock ) ;
if ( ret )
return ret ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
return 0 ;
}
2016-11-16 23:51:29 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_register_notif_cb ) ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
/**
2015-09-10 10:18:05 +03:00
* mei_cldev_get_drvdata - driver data getter
2015-07-23 15:08:35 +03:00
*
* @ cldev : mei client device
*
* Return : driver private data
*/
2015-09-10 10:18:05 +03:00
void * mei_cldev_get_drvdata ( const struct mei_cl_device * cldev )
2015-07-23 15:08:35 +03:00
{
return dev_get_drvdata ( & cldev - > dev ) ;
2013-03-27 19:29:53 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_get_drvdata ) ;
2013-03-27 19:29:53 +04:00
2015-07-23 15:08:35 +03:00
/**
2015-09-10 10:18:05 +03:00
* mei_cldev_set_drvdata - driver data setter
2015-07-23 15:08:35 +03:00
*
* @ cldev : mei client device
* @ data : data to store
*/
2015-09-10 10:18:05 +03:00
void mei_cldev_set_drvdata ( struct mei_cl_device * cldev , void * data )
2013-03-27 19:29:53 +04:00
{
2015-07-23 15:08:35 +03:00
dev_set_drvdata ( & cldev - > dev , data ) ;
2013-03-27 19:29:53 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_set_drvdata ) ;
2013-03-27 19:29:54 +04:00
2015-09-10 10:18:02 +03:00
/**
* mei_cldev_uuid - return uuid of the underlying me client
*
* @ cldev : mei client device
*
* Return : me client uuid
*/
const uuid_le * mei_cldev_uuid ( const struct mei_cl_device * cldev )
{
return mei_me_cl_uuid ( cldev - > me_cl ) ;
}
EXPORT_SYMBOL_GPL ( mei_cldev_uuid ) ;
/**
* mei_cldev_ver - return protocol version of the underlying me client
*
* @ cldev : mei client device
*
* Return : me client protocol version
*/
u8 mei_cldev_ver ( const struct mei_cl_device * cldev )
{
return mei_me_cl_ver ( cldev - > me_cl ) ;
}
EXPORT_SYMBOL_GPL ( mei_cldev_ver ) ;
2015-09-10 10:18:03 +03:00
/**
* mei_cldev_enabled - check whether the device is enabled
*
* @ cldev : mei client device
*
* Return : true if me client is initialized and connected
*/
bool mei_cldev_enabled ( struct mei_cl_device * cldev )
{
2016-11-16 23:51:28 +03:00
return mei_cl_is_connected ( cldev - > cl ) ;
2015-09-10 10:18:03 +03:00
}
EXPORT_SYMBOL_GPL ( mei_cldev_enabled ) ;
2018-02-25 21:07:04 +03:00
/**
* mei_cl_bus_module_get - acquire module of the underlying
* hw driver .
*
* @ cldev : mei client device
*
* Return : true on success ; false if the module was removed .
*/
static bool mei_cl_bus_module_get ( struct mei_cl_device * cldev )
{
return try_module_get ( cldev - > bus - > dev - > driver - > owner ) ;
}
/**
* mei_cl_bus_module_put - release the underlying hw module .
*
* @ cldev : mei client device
*/
static void mei_cl_bus_module_put ( struct mei_cl_device * cldev )
{
module_put ( cldev - > bus - > dev - > driver - > owner ) ;
}
2015-07-23 15:08:35 +03:00
/**
2016-12-14 18:56:51 +03:00
* mei_cldev_enable - enable me client device
2015-07-23 15:08:35 +03:00
* create connection with me client
*
* @ cldev : me client device
*
* Return : 0 on success and < 0 on error
*/
2015-09-10 10:18:05 +03:00
int mei_cldev_enable ( struct mei_cl_device * cldev )
2013-03-27 19:29:54 +04:00
{
2015-07-23 15:08:47 +03:00
struct mei_device * bus = cldev - > bus ;
struct mei_cl * cl ;
int ret ;
2013-03-27 19:29:54 +04:00
2015-07-23 15:08:47 +03:00
cl = cldev - > cl ;
2013-03-27 19:29:54 +04:00
2018-08-27 22:40:16 +03:00
mutex_lock ( & bus - > device_lock ) ;
2016-11-16 23:51:28 +03:00
if ( cl - > state = = MEI_FILE_UNINITIALIZED ) {
ret = mei_cl_link ( cl ) ;
if ( ret )
2018-08-27 22:40:16 +03:00
goto out ;
2015-07-23 15:08:47 +03:00
/* update pointers */
cl - > cldev = cldev ;
}
2013-03-27 19:29:54 +04:00
2015-07-23 15:08:35 +03:00
if ( mei_cl_is_connected ( cl ) ) {
2015-07-23 15:08:47 +03:00
ret = 0 ;
goto out ;
2015-07-23 15:08:35 +03:00
}
2013-03-27 19:29:54 +04:00
2015-07-23 15:08:47 +03:00
if ( ! mei_me_cl_is_active ( cldev - > me_cl ) ) {
dev_err ( & cldev - > dev , " me client is not active \n " ) ;
ret = - ENOTTY ;
goto out ;
2015-07-23 15:08:35 +03:00
}
2015-07-23 15:08:47 +03:00
ret = mei_cl_connect ( cl , cldev - > me_cl , NULL ) ;
2019-02-25 12:09:28 +03:00
if ( ret < 0 )
2015-07-23 15:08:47 +03:00
dev_err ( & cldev - > dev , " cannot connect \n " ) ;
out :
2015-07-23 15:08:35 +03:00
mutex_unlock ( & bus - > device_lock ) ;
2015-07-23 15:08:47 +03:00
return ret ;
2013-03-27 19:29:54 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_enable ) ;
2013-03-27 19:29:55 +04:00
2017-01-27 17:32:40 +03:00
/**
* mei_cldev_unregister_callbacks - internal wrapper for unregistering
* callbacks .
*
* @ cldev : client device
*/
static void mei_cldev_unregister_callbacks ( struct mei_cl_device * cldev )
{
if ( cldev - > rx_cb ) {
cancel_work_sync ( & cldev - > rx_work ) ;
cldev - > rx_cb = NULL ;
}
if ( cldev - > notif_cb ) {
cancel_work_sync ( & cldev - > notif_work ) ;
cldev - > notif_cb = NULL ;
}
}
2015-07-23 15:08:35 +03:00
/**
2015-09-10 10:18:05 +03:00
* mei_cldev_disable - disable me client device
2015-07-23 15:08:35 +03:00
* disconnect form the me client
*
* @ cldev : me client device
*
* Return : 0 on success and < 0 on error
*/
2015-09-10 10:18:05 +03:00
int mei_cldev_disable ( struct mei_cl_device * cldev )
2013-03-27 19:29:55 +04:00
{
2015-07-23 15:08:33 +03:00
struct mei_device * bus ;
2015-07-23 15:08:47 +03:00
struct mei_cl * cl ;
int err ;
2013-03-27 19:29:55 +04:00
2016-11-16 23:51:28 +03:00
if ( ! cldev )
2013-03-27 19:29:55 +04:00
return - ENODEV ;
2015-07-23 15:08:47 +03:00
cl = cldev - > cl ;
bus = cldev - > bus ;
2013-04-08 22:56:37 +04:00
2017-01-27 17:32:40 +03:00
mei_cldev_unregister_callbacks ( cldev ) ;
2015-07-23 15:08:35 +03:00
mutex_lock ( & bus - > device_lock ) ;
2013-04-08 22:56:37 +04:00
2015-07-23 15:08:35 +03:00
if ( ! mei_cl_is_connected ( cl ) ) {
2017-12-12 14:27:06 +03:00
dev_dbg ( bus - > dev , " Already disconnected \n " ) ;
err = 0 ;
goto out ;
}
2015-07-23 15:08:35 +03:00
err = mei_cl_disconnect ( cl ) ;
2015-07-23 15:08:47 +03:00
if ( err < 0 )
2017-12-12 14:27:06 +03:00
dev_err ( bus - > dev , " Could not disconnect from the ME client \n " ) ;
2013-03-27 19:29:55 +04:00
2018-08-27 22:40:15 +03:00
out :
2015-07-23 15:08:35 +03:00
/* Flush queues and remove any pending read */
mei_cl_flush_queues ( cl , NULL ) ;
2015-07-23 15:08:47 +03:00
mei_cl_unlink ( cl ) ;
2015-07-23 15:08:33 +03:00
mutex_unlock ( & bus - > device_lock ) ;
2015-07-23 15:08:35 +03:00
return err ;
2013-03-27 19:29:55 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_disable ) ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:39 +03:00
/**
* mei_cl_device_find - find matching entry in the driver id table
*
* @ cldev : me client device
* @ cldrv : me client driver
*
* Return : id on success ; NULL if no id is matching
*/
static const
struct mei_cl_device_id * mei_cl_device_find ( struct mei_cl_device * cldev ,
struct mei_cl_driver * cldrv )
2013-03-27 19:29:55 +04:00
{
2015-07-23 15:08:35 +03:00
const struct mei_cl_device_id * id ;
const uuid_le * uuid ;
2015-09-10 10:18:01 +03:00
u8 version ;
bool match ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
uuid = mei_me_cl_uuid ( cldev - > me_cl ) ;
2015-09-10 10:18:01 +03:00
version = mei_me_cl_ver ( cldev - > me_cl ) ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
id = cldrv - > id_table ;
while ( uuid_le_cmp ( NULL_UUID_LE , id - > uuid ) ) {
if ( ! uuid_le_cmp ( * uuid , id - > uuid ) ) {
2015-09-10 10:18:01 +03:00
match = true ;
2015-07-23 15:08:39 +03:00
2015-09-10 10:18:01 +03:00
if ( cldev - > name [ 0 ] )
if ( strncmp ( cldev - > name , id - > name ,
sizeof ( id - > name ) ) )
match = false ;
2015-07-23 15:08:39 +03:00
2015-09-10 10:18:01 +03:00
if ( id - > version ! = MEI_CL_VERSION_ANY )
if ( id - > version ! = version )
match = false ;
if ( match )
2015-07-23 15:08:39 +03:00
return id ;
2015-07-23 15:08:35 +03:00
}
2013-09-02 14:29:46 +04:00
2015-07-23 15:08:35 +03:00
id + + ;
}
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:39 +03:00
return NULL ;
}
/**
* mei_cl_device_match - device match function
*
* @ dev : device
* @ drv : driver
*
* Return : 1 if matching device was found 0 otherwise
*/
static int mei_cl_device_match ( struct device * dev , struct device_driver * drv )
{
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
struct mei_cl_driver * cldrv = to_mei_cl_driver ( drv ) ;
const struct mei_cl_device_id * found_id ;
if ( ! cldev )
return 0 ;
2015-07-23 15:08:43 +03:00
if ( ! cldev - > do_match )
return 0 ;
2015-07-23 15:08:39 +03:00
if ( ! cldrv | | ! cldrv - > id_table )
return 0 ;
found_id = mei_cl_device_find ( cldev , cldrv ) ;
if ( found_id )
return 1 ;
2015-07-23 15:08:35 +03:00
return 0 ;
}
2013-09-02 14:29:46 +04:00
2015-07-23 15:08:40 +03:00
/**
* mei_cl_device_probe - bus probe function
*
* @ dev : device
*
* Return : 0 on success ; < 0 otherwise
*/
2015-07-23 15:08:35 +03:00
static int mei_cl_device_probe ( struct device * dev )
{
2015-07-23 15:08:40 +03:00
struct mei_cl_device * cldev ;
2015-07-23 15:08:35 +03:00
struct mei_cl_driver * cldrv ;
2015-07-23 15:08:40 +03:00
const struct mei_cl_device_id * id ;
2016-04-01 23:53:01 +03:00
int ret ;
2015-07-23 15:08:40 +03:00
cldev = to_mei_cl_device ( dev ) ;
cldrv = to_mei_cl_driver ( dev - > driver ) ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
if ( ! cldev )
return 0 ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
if ( ! cldrv | | ! cldrv - > probe )
return - ENODEV ;
2015-07-23 15:08:40 +03:00
id = mei_cl_device_find ( cldev , cldrv ) ;
if ( ! id )
return - ENODEV ;
2015-07-23 15:08:35 +03:00
2019-02-25 12:09:28 +03:00
if ( ! mei_cl_bus_module_get ( cldev ) ) {
dev_err ( & cldev - > dev , " get hw module failed " ) ;
return - ENODEV ;
}
2016-04-01 23:53:01 +03:00
ret = cldrv - > probe ( cldev , id ) ;
2019-02-25 12:09:28 +03:00
if ( ret ) {
mei_cl_bus_module_put ( cldev ) ;
2016-04-01 23:53:01 +03:00
return ret ;
2019-02-25 12:09:28 +03:00
}
2015-07-23 15:08:35 +03:00
2016-04-01 23:53:01 +03:00
__module_get ( THIS_MODULE ) ;
return 0 ;
2015-07-23 15:08:35 +03:00
}
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:40 +03:00
/**
* mei_cl_device_remove - remove device from the bus
*
* @ dev : device
*
* Return : 0 on success ; < 0 otherwise
*/
2015-07-23 15:08:35 +03:00
static int mei_cl_device_remove ( struct device * dev )
{
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
struct mei_cl_driver * cldrv ;
2015-07-23 15:08:40 +03:00
int ret = 0 ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
if ( ! cldev | | ! dev - > driver )
return 0 ;
2017-01-27 17:32:38 +03:00
cldrv = to_mei_cl_driver ( dev - > driver ) ;
if ( cldrv - > remove )
ret = cldrv - > remove ( cldev ) ;
2017-01-27 17:32:40 +03:00
mei_cldev_unregister_callbacks ( cldev ) ;
2015-02-10 11:39:36 +03:00
2019-02-25 12:09:28 +03:00
mei_cl_bus_module_put ( cldev ) ;
2015-07-23 15:08:40 +03:00
module_put ( THIS_MODULE ) ;
dev - > driver = NULL ;
return ret ;
2013-03-27 19:29:55 +04:00
}
2015-07-23 15:08:35 +03:00
static ssize_t name_show ( struct device * dev , struct device_attribute * a ,
char * buf )
2013-03-27 19:29:55 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
2013-03-27 19:29:55 +04:00
2016-03-24 11:38:04 +03:00
return scnprintf ( buf , PAGE_SIZE , " %s " , cldev - > name ) ;
2013-03-27 19:29:55 +04:00
}
2015-07-23 15:08:35 +03:00
static DEVICE_ATTR_RO ( name ) ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
static ssize_t uuid_show ( struct device * dev , struct device_attribute * a ,
char * buf )
2013-03-27 19:29:55 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
const uuid_le * uuid = mei_me_cl_uuid ( cldev - > me_cl ) ;
2013-03-27 19:29:55 +04:00
2016-03-24 11:38:04 +03:00
return scnprintf ( buf , PAGE_SIZE , " %pUl " , uuid ) ;
2013-03-27 19:29:55 +04:00
}
2015-07-23 15:08:35 +03:00
static DEVICE_ATTR_RO ( uuid ) ;
2013-03-27 19:29:55 +04:00
2015-09-10 10:18:00 +03:00
static ssize_t version_show ( struct device * dev , struct device_attribute * a ,
char * buf )
{
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
u8 version = mei_me_cl_ver ( cldev - > me_cl ) ;
2016-03-24 11:38:04 +03:00
return scnprintf ( buf , PAGE_SIZE , " %02X " , version ) ;
2015-09-10 10:18:00 +03:00
}
static DEVICE_ATTR_RO ( version ) ;
2015-07-23 15:08:35 +03:00
static ssize_t modalias_show ( struct device * dev , struct device_attribute * a ,
char * buf )
2013-03-27 19:29:55 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
const uuid_le * uuid = mei_me_cl_uuid ( cldev - > me_cl ) ;
2017-05-29 22:08:24 +03:00
u8 version = mei_me_cl_ver ( cldev - > me_cl ) ;
2013-03-27 19:29:55 +04:00
2017-05-29 22:08:24 +03:00
return scnprintf ( buf , PAGE_SIZE , " mei:%s:%pUl:%02X: " ,
cldev - > name , uuid , version ) ;
2013-03-27 19:29:55 +04:00
}
2015-07-23 15:08:35 +03:00
static DEVICE_ATTR_RO ( modalias ) ;
2013-03-27 19:29:55 +04:00
2015-09-10 10:18:05 +03:00
static struct attribute * mei_cldev_attrs [ ] = {
2015-07-23 15:08:35 +03:00
& dev_attr_name . attr ,
& dev_attr_uuid . attr ,
2015-09-10 10:18:00 +03:00
& dev_attr_version . attr ,
2015-07-23 15:08:35 +03:00
& dev_attr_modalias . attr ,
NULL ,
} ;
2015-09-10 10:18:05 +03:00
ATTRIBUTE_GROUPS ( mei_cldev ) ;
2015-07-23 15:08:35 +03:00
2015-07-23 15:08:36 +03:00
/**
* mei_cl_device_uevent - me client bus uevent handler
*
* @ dev : device
* @ env : uevent kobject
*
* Return : 0 on success - ENOMEM on when add_uevent_var fails
*/
static int mei_cl_device_uevent ( struct device * dev , struct kobj_uevent_env * env )
2013-03-27 19:29:55 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
const uuid_le * uuid = mei_me_cl_uuid ( cldev - > me_cl ) ;
2015-09-10 10:18:00 +03:00
u8 version = mei_me_cl_ver ( cldev - > me_cl ) ;
if ( add_uevent_var ( env , " MEI_CL_VERSION=%d " , version ) )
return - ENOMEM ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
if ( add_uevent_var ( env , " MEI_CL_UUID=%pUl " , uuid ) )
return - ENOMEM ;
2013-03-27 19:29:55 +04:00
2015-07-23 15:08:35 +03:00
if ( add_uevent_var ( env , " MEI_CL_NAME=%s " , cldev - > name ) )
return - ENOMEM ;
2015-09-10 10:18:01 +03:00
if ( add_uevent_var ( env , " MODALIAS=mei:%s:%pUl:%02X: " ,
cldev - > name , uuid , version ) )
2015-07-23 15:08:35 +03:00
return - ENOMEM ;
2013-03-27 19:29:55 +04:00
return 0 ;
}
2013-03-27 19:29:57 +04:00
2015-07-23 15:08:35 +03:00
static struct bus_type mei_cl_bus_type = {
. name = " mei " ,
2015-09-10 10:18:05 +03:00
. dev_groups = mei_cldev_groups ,
2015-07-23 15:08:35 +03:00
. match = mei_cl_device_match ,
. probe = mei_cl_device_probe ,
. remove = mei_cl_device_remove ,
2015-07-23 15:08:36 +03:00
. uevent = mei_cl_device_uevent ,
2015-07-23 15:08:35 +03:00
} ;
2015-07-23 15:08:41 +03:00
static struct mei_device * mei_dev_bus_get ( struct mei_device * bus )
{
if ( bus )
get_device ( bus - > dev ) ;
return bus ;
}
static void mei_dev_bus_put ( struct mei_device * bus )
{
if ( bus )
put_device ( bus - > dev ) ;
}
2015-09-10 10:18:06 +03:00
static void mei_cl_bus_dev_release ( struct device * dev )
2013-03-27 19:29:59 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev = to_mei_cl_device ( dev ) ;
if ( ! cldev )
return ;
mei_me_cl_put ( cldev - > me_cl ) ;
2015-07-23 15:08:41 +03:00
mei_dev_bus_put ( cldev - > bus ) ;
2018-08-27 22:40:16 +03:00
mei_cl_unlink ( cldev - > cl ) ;
2016-11-16 23:51:28 +03:00
kfree ( cldev - > cl ) ;
2015-07-23 15:08:35 +03:00
kfree ( cldev ) ;
2013-03-27 19:29:59 +04:00
}
2017-08-19 11:22:16 +03:00
static const struct device_type mei_cl_device_type = {
2018-08-27 22:40:16 +03:00
. release = mei_cl_bus_dev_release ,
2015-07-23 15:08:35 +03:00
} ;
2015-10-28 15:34:35 +03:00
/**
* mei_cl_bus_set_name - set device name for me client device
*
* @ cldev : me client device
*/
static inline void mei_cl_bus_set_name ( struct mei_cl_device * cldev )
{
dev_set_name ( & cldev - > dev , " mei:%s:%pUl:%02X " ,
cldev - > name ,
mei_me_cl_uuid ( cldev - > me_cl ) ,
mei_me_cl_ver ( cldev - > me_cl ) ) ;
}
2015-07-23 15:08:43 +03:00
/**
2015-09-10 10:18:06 +03:00
* mei_cl_bus_dev_alloc - initialize and allocate mei client device
2015-07-23 15:08:43 +03:00
*
* @ bus : mei device
* @ me_cl : me client
*
* Return : allocated device structur or NULL on allocation failure
*/
2015-09-10 10:18:06 +03:00
static struct mei_cl_device * mei_cl_bus_dev_alloc ( struct mei_device * bus ,
struct mei_me_client * me_cl )
2015-07-23 15:08:43 +03:00
{
struct mei_cl_device * cldev ;
2016-11-16 23:51:28 +03:00
struct mei_cl * cl ;
2015-07-23 15:08:43 +03:00
cldev = kzalloc ( sizeof ( struct mei_cl_device ) , GFP_KERNEL ) ;
if ( ! cldev )
return NULL ;
2016-11-16 23:51:28 +03:00
cl = mei_cl_allocate ( bus ) ;
if ( ! cl ) {
kfree ( cldev ) ;
return NULL ;
}
2015-07-23 15:08:43 +03:00
device_initialize ( & cldev - > dev ) ;
cldev - > dev . parent = bus - > dev ;
cldev - > dev . bus = & mei_cl_bus_type ;
cldev - > dev . type = & mei_cl_device_type ;
cldev - > bus = mei_dev_bus_get ( bus ) ;
cldev - > me_cl = mei_me_cl_get ( me_cl ) ;
2016-11-16 23:51:28 +03:00
cldev - > cl = cl ;
2015-10-28 15:34:35 +03:00
mei_cl_bus_set_name ( cldev ) ;
2015-07-23 15:08:43 +03:00
cldev - > is_added = 0 ;
INIT_LIST_HEAD ( & cldev - > bus_list ) ;
return cldev ;
}
/**
* mei_cl_dev_setup - setup me client device
* run fix up routines and set the device name
*
* @ bus : mei device
* @ cldev : me client device
*
* Return : true if the device is eligible for enumeration
*/
2015-09-10 10:18:06 +03:00
static bool mei_cl_bus_dev_setup ( struct mei_device * bus ,
struct mei_cl_device * cldev )
2015-07-23 15:08:43 +03:00
{
cldev - > do_match = 1 ;
2015-09-10 10:18:06 +03:00
mei_cl_bus_dev_fixup ( cldev ) ;
2015-07-23 15:08:43 +03:00
2015-10-28 15:34:35 +03:00
/* the device name can change during fix up */
2015-07-23 15:08:43 +03:00
if ( cldev - > do_match )
2015-10-28 15:34:35 +03:00
mei_cl_bus_set_name ( cldev ) ;
2015-07-23 15:08:43 +03:00
return cldev - > do_match = = 1 ;
}
/**
* mei_cl_bus_dev_add - add me client devices
*
* @ cldev : me client device
*
* Return : 0 on success ; < 0 on failre
*/
static int mei_cl_bus_dev_add ( struct mei_cl_device * cldev )
{
int ret ;
2015-09-10 10:18:01 +03:00
dev_dbg ( cldev - > bus - > dev , " adding %pUL:%02X \n " ,
mei_me_cl_uuid ( cldev - > me_cl ) ,
mei_me_cl_ver ( cldev - > me_cl ) ) ;
2015-07-23 15:08:43 +03:00
ret = device_add ( & cldev - > dev ) ;
if ( ! ret )
cldev - > is_added = 1 ;
return ret ;
}
2015-07-23 15:08:47 +03:00
/**
* mei_cl_bus_dev_stop - stop the driver
*
* @ cldev : me client device
*/
static void mei_cl_bus_dev_stop ( struct mei_cl_device * cldev )
{
if ( cldev - > is_added )
device_release_driver ( & cldev - > dev ) ;
}
/**
* mei_cl_bus_dev_destroy - destroy me client devices object
*
* @ cldev : me client device
2015-10-28 15:34:34 +03:00
*
* Locking : called under " dev->cl_bus_lock " lock
2015-07-23 15:08:47 +03:00
*/
static void mei_cl_bus_dev_destroy ( struct mei_cl_device * cldev )
{
2015-10-28 15:34:34 +03:00
WARN_ON ( ! mutex_is_locked ( & cldev - > bus - > cl_bus_lock ) ) ;
2015-07-23 15:08:47 +03:00
if ( ! cldev - > is_added )
return ;
device_del ( & cldev - > dev ) ;
list_del_init ( & cldev - > bus_list ) ;
cldev - > is_added = 0 ;
put_device ( & cldev - > dev ) ;
}
/**
* mei_cl_bus_remove_device - remove a devices form the bus
*
* @ cldev : me client device
*/
static void mei_cl_bus_remove_device ( struct mei_cl_device * cldev )
{
mei_cl_bus_dev_stop ( cldev ) ;
mei_cl_bus_dev_destroy ( cldev ) ;
}
/**
* mei_cl_bus_remove_devices - remove all devices form the bus
*
* @ bus : mei device
*/
void mei_cl_bus_remove_devices ( struct mei_device * bus )
{
struct mei_cl_device * cldev , * next ;
2015-10-28 15:34:34 +03:00
mutex_lock ( & bus - > cl_bus_lock ) ;
2015-07-23 15:08:47 +03:00
list_for_each_entry_safe ( cldev , next , & bus - > device_list , bus_list )
mei_cl_bus_remove_device ( cldev ) ;
2015-10-28 15:34:34 +03:00
mutex_unlock ( & bus - > cl_bus_lock ) ;
2015-07-23 15:08:47 +03:00
}
/**
2015-09-10 10:18:06 +03:00
* mei_cl_bus_dev_init - allocate and initializes an mei client devices
2015-07-23 15:08:47 +03:00
* based on me client
*
* @ bus : mei device
* @ me_cl : me client
2015-10-28 15:34:34 +03:00
*
* Locking : called under " dev->cl_bus_lock " lock
2015-07-23 15:08:47 +03:00
*/
2015-09-10 10:18:06 +03:00
static void mei_cl_bus_dev_init ( struct mei_device * bus ,
struct mei_me_client * me_cl )
2013-04-09 02:51:38 +04:00
{
2015-07-23 15:08:35 +03:00
struct mei_cl_device * cldev ;
2015-07-23 15:08:47 +03:00
2015-10-28 15:34:34 +03:00
WARN_ON ( ! mutex_is_locked ( & bus - > cl_bus_lock ) ) ;
2015-07-23 15:08:47 +03:00
dev_dbg ( bus - > dev , " initializing %pUl " , mei_me_cl_uuid ( me_cl ) ) ;
if ( me_cl - > bus_added )
return ;
2013-04-09 02:51:38 +04:00
2015-09-10 10:18:06 +03:00
cldev = mei_cl_bus_dev_alloc ( bus , me_cl ) ;
2015-07-23 15:08:35 +03:00
if ( ! cldev )
2015-07-23 15:08:47 +03:00
return ;
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:47 +03:00
me_cl - > bus_added = true ;
list_add_tail ( & cldev - > bus_list , & bus - > device_list ) ;
2015-05-04 09:43:53 +03:00
2015-07-23 15:08:47 +03:00
}
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:47 +03:00
/**
* mei_cl_bus_rescan - scan me clients list and add create
* devices for eligible clients
*
* @ bus : mei device
*/
2017-04-30 13:12:10 +03:00
static void mei_cl_bus_rescan ( struct mei_device * bus )
2015-07-23 15:08:47 +03:00
{
struct mei_cl_device * cldev , * n ;
struct mei_me_client * me_cl ;
2013-04-09 02:51:38 +04:00
2015-10-28 15:34:34 +03:00
mutex_lock ( & bus - > cl_bus_lock ) ;
2015-07-23 15:08:47 +03:00
down_read ( & bus - > me_clients_rwsem ) ;
list_for_each_entry ( me_cl , & bus - > me_clients , list )
2015-09-10 10:18:06 +03:00
mei_cl_bus_dev_init ( bus , me_cl ) ;
2015-07-23 15:08:47 +03:00
up_read ( & bus - > me_clients_rwsem ) ;
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:47 +03:00
list_for_each_entry_safe ( cldev , n , & bus - > device_list , bus_list ) {
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:47 +03:00
if ( ! mei_me_cl_is_active ( cldev - > me_cl ) ) {
mei_cl_bus_remove_device ( cldev ) ;
continue ;
}
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:47 +03:00
if ( cldev - > is_added )
continue ;
2015-09-10 10:18:06 +03:00
if ( mei_cl_bus_dev_setup ( bus , cldev ) )
2015-07-23 15:08:47 +03:00
mei_cl_bus_dev_add ( cldev ) ;
else {
list_del_init ( & cldev - > bus_list ) ;
put_device ( & cldev - > dev ) ;
}
}
mutex_unlock ( & bus - > cl_bus_lock ) ;
dev_dbg ( bus - > dev , " rescan end " ) ;
2015-07-23 15:08:35 +03:00
}
2013-04-09 02:51:38 +04:00
2016-02-08 00:35:41 +03:00
void mei_cl_bus_rescan_work ( struct work_struct * work )
{
struct mei_device * bus =
container_of ( work , struct mei_device , bus_rescan_work ) ;
mei_cl_bus_rescan ( bus ) ;
}
2015-09-10 10:18:05 +03:00
int __mei_cldev_driver_register ( struct mei_cl_driver * cldrv ,
struct module * owner )
2015-07-23 15:08:35 +03:00
{
int err ;
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:35 +03:00
cldrv - > driver . name = cldrv - > name ;
cldrv - > driver . owner = owner ;
cldrv - > driver . bus = & mei_cl_bus_type ;
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:35 +03:00
err = driver_register ( & cldrv - > driver ) ;
if ( err )
return err ;
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:35 +03:00
pr_debug ( " mei: driver [%s] registered \n " , cldrv - > driver . name ) ;
2013-04-09 02:51:38 +04:00
2015-07-23 15:08:35 +03:00
return 0 ;
2013-04-09 02:51:38 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( __mei_cldev_driver_register ) ;
2013-04-09 02:51:38 +04:00
2015-09-10 10:18:05 +03:00
void mei_cldev_driver_unregister ( struct mei_cl_driver * cldrv )
2013-03-27 19:29:57 +04:00
{
2015-07-23 15:08:35 +03:00
driver_unregister ( & cldrv - > driver ) ;
2013-03-27 19:29:57 +04:00
2015-07-23 15:08:35 +03:00
pr_debug ( " mei: driver [%s] unregistered \n " , cldrv - > driver . name ) ;
2013-03-27 19:29:57 +04:00
}
2015-09-10 10:18:05 +03:00
EXPORT_SYMBOL_GPL ( mei_cldev_driver_unregister ) ;
2013-03-27 19:29:57 +04:00
2015-07-23 15:08:47 +03:00
2013-03-27 19:29:57 +04:00
int __init mei_cl_bus_init ( void )
{
return bus_register ( & mei_cl_bus_type ) ;
}
void __exit mei_cl_bus_exit ( void )
{
bus_unregister ( & mei_cl_bus_type ) ;
}